{
 "cells": [
  {
   "cell_type": "code",
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "WKUPkA0TJzbW",
    "outputId": "909eba98-db9c-482f-fb6b-b20b68bce069",
    "ExecuteTime": {
     "end_time": "2025-02-05T05:50:20.394061Z",
     "start_time": "2025-02-05T05:50:16.435780Z"
    }
   },
   "source": [
    "import matplotlib as mpl\n",
    "import matplotlib.pyplot as plt\n",
    "%matplotlib inline\n",
    "import numpy as np\n",
    "import sklearn\n",
    "import pandas as pd\n",
    "import os\n",
    "import sys\n",
    "import time\n",
    "from tqdm.auto import tqdm\n",
    "import torch\n",
    "import torch.nn as nn\n",
    "import torch.nn.functional as F\n",
    "\n",
    "print(sys.version_info)\n",
    "for module in mpl, np, pd, sklearn, torch:\n",
    "    print(module.__name__, module.__version__)\n",
    "\n",
    "device = torch.device(\"cuda:0\") if torch.cuda.is_available() else torch.device(\"cpu\")\n",
    "print(device)\n",
    "\n",
    "seed = 42\n",
    "torch.manual_seed(seed)\n",
    "torch.cuda.manual_seed_all(seed)\n",
    "np.random.seed(seed)\n"
   ],
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "sys.version_info(major=3, minor=12, micro=3, releaselevel='final', serial=0)\n",
      "matplotlib 3.10.0\n",
      "numpy 1.26.4\n",
      "pandas 2.2.3\n",
      "sklearn 1.6.1\n",
      "torch 2.5.1+cpu\n",
      "cpu\n"
     ]
    }
   ],
   "execution_count": 1
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "pSNcMyqvJzbY"
   },
   "source": [
    "## 数据加载"
   ]
  },
  {
   "cell_type": "code",
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "Dm1DrSCLJzbZ",
    "outputId": "ab7f8ef9-6119-4d2b-df23-7cc04f617802",
    "ExecuteTime": {
     "end_time": "2025-02-05T05:50:20.529731Z",
     "start_time": "2025-02-05T05:50:20.395995Z"
    }
   },
   "source": [
    "import unicodedata\n",
    "import re\n",
    "from sklearn.model_selection import train_test_split\n",
    "\n",
    "#因为西班牙语有一些是特殊字符，所以我们需要unicode转ascii，\n",
    "# 这样值变小了，因为unicode太大\n",
    "def unicode_to_ascii(s):\n",
    "    # NFD是转换方法，把每一个字节拆开，Mn是西班牙重音，所以去除\n",
    "    return ''.join(c for c in unicodedata.normalize('NFD', s) if unicodedata.category(c) != 'Mn')\n",
    "\n",
    "#下面我们找个样本测试一下\n",
    "# 加u代表对字符串进行unicode编码\n",
    "en_sentence = u\"May I borrow this book?\"\n",
    "sp_sentence = u\"¿Puedo tomar prestado este libro?\"\n",
    "\n",
    "print(unicode_to_ascii(en_sentence))\n",
    "print(unicode_to_ascii(sp_sentence))\n",
    "\n",
    "\n"
   ],
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "May I borrow this book?\n",
      "¿Puedo tomar prestado este libro?\n"
     ]
    }
   ],
   "execution_count": 2
  },
  {
   "cell_type": "code",
   "source": [
    "def preprocess_sentence(w):\n",
    "    #变为小写，去掉多余的空格，变成小写，id少一些\n",
    "    w = unicode_to_ascii(w.lower().strip())\n",
    "\n",
    "    # 在单词与跟在其后的标点符号之间插入一个空格\n",
    "    # eg: \"he is a boy.\" => \"he is a boy . \"\n",
    "    # Reference:- https://stackoverflow.com/questions/3645931/python-padding-punctuation-with-white-spaces-keeping-punctuation\n",
    "    w = re.sub(r\"([?.!,¿])\", r\" \\1 \", w)\n",
    "    #因为可能有多余空格，替换为一个空格，所以处理一下\n",
    "    w = re.sub(r'[\" \"]+', \" \", w)\n",
    "\n",
    "    # 除了 (a-z, A-Z, \".\", \"?\", \"!\", \",\")，将所有字符替换为空格\n",
    "    w = re.sub(r\"[^a-zA-Z?.!,¿]+\", \" \", w)\n",
    "    \n",
    "    w = w.rstrip().strip()\n",
    "\n",
    "    return w\n",
    "\n",
    "print(preprocess_sentence(en_sentence))\n",
    "print(preprocess_sentence(sp_sentence))\n",
    "print(preprocess_sentence(sp_sentence).encode('utf-8'))  #¿是占用两个字节的"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2025-02-05T05:50:20.535040Z",
     "start_time": "2025-02-05T05:50:20.530726Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "may i borrow this book ?\n",
      "¿ puedo tomar prestado este libro ?\n",
      "b'\\xc2\\xbf puedo tomar prestado este libro ?'\n"
     ]
    }
   ],
   "execution_count": 3
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "YyJksrNmJzba"
   },
   "source": [
    "Dataset"
   ]
  },
  {
   "cell_type": "code",
   "source": [
    "# zip例子——>把[en,sp]中的en和sp分别打包成元组，然后打包成列表\n",
    "a = [[1,2],[4,5],[7,8]]\n",
    "zipped = list(zip(*a))\n",
    "print(zipped)\n",
    "en,sp = list(zip(*a))\n",
    "print(en)\n",
    "print(sp)"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2025-02-05T05:56:24.619551Z",
     "start_time": "2025-02-05T05:56:24.616Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[(1, 4, 7), (2, 5, 8)]\n",
      "(1, 4, 7)\n",
      "(2, 5, 8)\n"
     ]
    }
   ],
   "execution_count": 7
  },
  {
   "cell_type": "code",
   "source": [
    "split_index1 = np.random.choice(a=[\"train\", \"test\"], replace=True, p=[0.9, 0.1], size=100)\n",
    "split_index1"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2025-02-05T06:17:55.827674Z",
     "start_time": "2025-02-05T06:17:55.821626Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array(['train', 'train', 'train', 'train', 'train', 'train', 'train',\n",
       "       'train', 'train', 'train', 'train', 'train', 'test', 'train',\n",
       "       'train', 'train', 'train', 'train', 'train', 'train', 'train',\n",
       "       'train', 'train', 'train', 'train', 'train', 'train', 'test',\n",
       "       'train', 'train', 'train', 'train', 'train', 'train', 'train',\n",
       "       'train', 'test', 'train', 'train', 'train', 'train', 'train',\n",
       "       'train', 'train', 'test', 'train', 'train', 'train', 'train',\n",
       "       'train', 'train', 'train', 'test', 'train', 'test', 'train',\n",
       "       'train', 'train', 'train', 'train', 'test', 'train', 'train',\n",
       "       'train', 'train', 'train', 'train', 'test', 'train', 'train',\n",
       "       'train', 'train', 'train', 'train', 'train', 'train', 'train',\n",
       "       'train', 'train', 'train', 'train', 'train', 'train', 'train',\n",
       "       'train', 'train', 'train', 'train', 'train', 'train', 'train',\n",
       "       'train', 'train', 'train', 'train', 'train', 'train', 'test',\n",
       "       'train', 'train'], dtype='<U5')"
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "execution_count": 15
  },
  {
   "cell_type": "code",
   "metadata": {
    "id": "-VnoIKhaJzba",
    "ExecuteTime": {
     "end_time": "2025-02-05T06:00:40.695111Z",
     "start_time": "2025-02-05T06:00:35.842250Z"
    }
   },
   "source": [
    "from pathlib import Path\n",
    "from torch.utils.data import Dataset, DataLoader\n",
    "\n",
    "class LangPairDataset(Dataset):\n",
    "    fpath = Path(r\"./data_spa_en/spa.txt\") # 数据文件路径\n",
    "    cache_path = Path(r\"./.cache/lang_pair.npy\") # 缓存文件路径\n",
    "    split_index = np.random.choice(a=[\"train\", \"test\"], replace=True, p=[0.9, 0.1], size=118964) #按照9:1划分训练集和测试集\n",
    "    def __init__(self, mode=\"train\", cache=False):\n",
    "        if cache or not self.cache_path.exists():# 如果没有缓存，或者缓存不存在，就处理一下数据\n",
    "            self.cache_path.parent.mkdir(parents=True, exist_ok=True) # 创建缓存文件夹，如果存在就忽略\n",
    "            with open(self.fpath, \"r\", encoding=\"utf8\") as file:\n",
    "                lines = file.readlines()\n",
    "                lang_pair = [[preprocess_sentence(w) for w in l.split('\\t')]  for l in lines] # 处理数据，变成list((trg, src))的形式\n",
    "                trg, src = zip(*lang_pair) #分离出目标语言和源语言\n",
    "                trg=np.array(trg) #转换为numpy数组\n",
    "                src=np.array(src) #转换为numpy数组\n",
    "                np.save(self.cache_path, {\"trg\": trg, \"src\": src})  # 保存为npy文件,方便下次直接读取,不用再处理\n",
    "        else:\n",
    "            lang_pair = np.load(self.cache_path, allow_pickle=True).item() # 读取npy文件，allow_pickle=True允许读取字典\n",
    "            trg = lang_pair[\"trg\"]\n",
    "            src = lang_pair[\"src\"]\n",
    "\n",
    "        self.trg = trg[self.split_index == mode] # 按照index拿到训练集的 标签语言 --英语\n",
    "        self.src = src[self.split_index == mode] # 按照index拿到训练集的源语言 --西班牙\n",
    "\n",
    "    def __getitem__(self, index):\n",
    "        return self.src[index], self.trg[index]\n",
    "\n",
    "    def __len__(self):\n",
    "        return len(self.src)\n",
    "\n",
    "\n",
    "train_ds = LangPairDataset(\"train\")\n",
    "test_ds = LangPairDataset(\"test\")"
   ],
   "outputs": [],
   "execution_count": 9
  },
  {
   "cell_type": "code",
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "knue-PUkJzbb",
    "outputId": "86c1d3c8-8bd2-4c7f-8576-7516c4767ec2",
    "ExecuteTime": {
     "end_time": "2025-02-05T06:02:34.302517Z",
     "start_time": "2025-02-05T06:02:34.296442Z"
    }
   },
   "source": "print(\"source: {}\\ntarget: {}\".format(*train_ds[-1]))  # *拆包",
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "source: si quieres sonar como un hablante nativo , debes estar dispuesto a practicar diciendo la misma frase una y otra vez de la misma manera en que un musico de banjo practica el mismo fraseo una y otra vez hasta que lo puedan tocar correctamente y en el tiempo esperado .\n",
      "target: if you want to sound like a native speaker , you must be willing to practice saying the same sentence over and over in the same way that banjo players practice the same phrase over and over until they can play it correctly and at the desired tempo .\n"
     ]
    }
   ],
   "execution_count": 12
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "9mzBlPtGJzbb"
   },
   "source": [
    "### Tokenizer\n",
    "\n",
    "这里有两种处理方式，分别对应着 encoder 和 decoder 的 word embedding 是否共享，这里实现不共享的方案。"
   ]
  },
  {
   "cell_type": "code",
   "metadata": {
    "id": "fMSIczSnJzbb",
    "ExecuteTime": {
     "end_time": "2025-02-05T07:06:38.958834Z",
     "start_time": "2025-02-05T07:06:38.381500Z"
    }
   },
   "source": [
    "from collections import Counter\n",
    "\n",
    "def get_word_idx(ds, mode=\"src\", threshold=1):\n",
    "    #载入词表，看下词表长度，词表就像英语字典\n",
    "    word2idx = {\n",
    "        \"[PAD]\": 0,     # 填充 token\n",
    "        \"[BOS]\": 1,     # begin of sentence\n",
    "        \"[UNK]\": 2,     # 未知 token\n",
    "        \"[EOS]\": 3,     # end of sentence\n",
    "    }\n",
    "    idx2word = {value: key for key, value in word2idx.items()}\n",
    "    index = len(idx2word)\n",
    "    # 如果数据集有很多个G，那是用for循环的，不能' '.join\n",
    "    word_list = \" \".join([pair[0 if mode==\"src\" else 1] for pair in ds]).split()\n",
    "    counter = Counter(word_list) # 统计词频,counter类似字典，key是单词，value是出现次数\n",
    "    print(\"word count:\", len(counter))\n",
    "\n",
    "    for token, count in counter.items():\n",
    "        if count >= threshold:#出现次数大于阈值的token加入词表\n",
    "            word2idx[token] = index #加入词表\n",
    "            idx2word[index] = token #加入反向词表\n",
    "            index += 1\n",
    "\n",
    "    return word2idx, idx2word\n",
    "\n",
    "src_word2idx, src_idx2word = get_word_idx(train_ds, \"src\") # 源语言词表\n",
    "trg_word2idx, trg_idx2word = get_word_idx(train_ds, \"trg\") # 目标语言词表"
   ],
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "word count: 23774\n",
      "word count: 12537\n"
     ]
    }
   ],
   "execution_count": 22
  },
  {
   "cell_type": "code",
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "9_IjY_wIJzbb",
    "outputId": "f2bf8be3-ec47-48e2-b743-1d2dbd511adc",
    "ExecuteTime": {
     "end_time": "2025-02-05T08:32:03.508224Z",
     "start_time": "2025-02-05T08:32:03.496138Z"
    }
   },
   "source": [
    "class Tokenizer:\n",
    "    def __init__(self, word2idx, idx2word, max_length=500, pad_idx=0, bos_idx=1, eos_idx=3, unk_idx=2):\n",
    "        self.word2idx = word2idx\n",
    "        self.idx2word = idx2word\n",
    "        self.max_length = max_length\n",
    "        self.pad_idx = pad_idx\n",
    "        self.bos_idx = bos_idx\n",
    "        self.eos_idx = eos_idx\n",
    "        self.unk_idx = unk_idx\n",
    "\n",
    "    def encode(self, text_list, padding_first=False, add_bos=True, add_eos=True, return_mask=False):\n",
    "        \"\"\"如果padding_first == True，则padding加载前面，否则加载后面\n",
    "        return_mask: 是否返回mask(掩码），mask用于指示哪些是padding的，哪些是真实的token\n",
    "        \"\"\"\n",
    "        # 一次处理一批text，所以用list\n",
    "        max_length = min(self.max_length, add_eos + add_bos + max([len(text) for text in text_list]))\n",
    "        indices_list = []\n",
    "        for text in text_list:\n",
    "            indices = [self.word2idx.get(word, self.unk_idx) for word in text[:max_length - add_bos - add_eos]] #如果词表中没有这个词，就用unk_idx代替，indices是一个list,里面是每个词的index,也就是一个样本的index\n",
    "            if add_bos:\n",
    "                indices = [self.bos_idx] + indices\n",
    "            if add_eos:\n",
    "                indices = indices + [self.eos_idx]\n",
    "            if padding_first:  # padding加载前面，超参可以调\n",
    "                indices = [self.pad_idx] * (max_length - len(indices)) + indices\n",
    "            else:  # padding加载后面\n",
    "                indices = indices + [self.pad_idx] * (max_length - len(indices))\n",
    "            indices_list.append(indices)\n",
    "        input_ids = torch.tensor(indices_list)  # 转换为tensor\n",
    "        # mask是一个和input_ids一样大小的tensor，0代表token，1代表padding，mask用于去除padding的影响\n",
    "        masks = (input_ids == self.pad_idx).to(dtype=torch.int64) \n",
    "        return input_ids if not return_mask else (input_ids, masks)\n",
    "\n",
    "\n",
    "    def decode(self, indices_list, remove_bos=True, remove_eos=True, remove_pad=True, split=False):\n",
    "        text_list = []\n",
    "        for indices in indices_list:\n",
    "            text = []\n",
    "            for index in indices:\n",
    "                word = self.idx2word.get(index, \"[UNK]\") #如果词表中没有这个词，就用unk_idx代替\n",
    "                if remove_bos and word == \"[BOS]\":\n",
    "                    continue\n",
    "                if remove_eos and word == \"[EOS]\":#如果到达eos，就结束\n",
    "                    break\n",
    "                if remove_pad and word == \"[PAD]\":#如果到达pad，就结束\n",
    "                    break\n",
    "                text.append(word) #单词添加到列表中\n",
    "            text_list.append(\" \".join(text) if not split else text) #把列表中的单词拼接，变为一个句子\n",
    "        return text_list\n",
    "\n",
    "#两个相对于1个toknizer的好处是embedding的参数量减少\n",
    "src_tokenizer = Tokenizer(word2idx=src_word2idx, idx2word=src_idx2word) #源语言tokenizer\n",
    "trg_tokenizer = Tokenizer(word2idx=trg_word2idx, idx2word=trg_idx2word) #目标语言tokenizer\n",
    "\n",
    "# trg_tokenizer.encode([[\"hello\"], [\"hello\", \"world\"]], add_bos=True, add_eos=False,return_mask=True)\n",
    "raw_text = [\"hello world\".split(), \"tokenize text datas with batch\".split(), \"this is a test\".split()]\n",
    "indices,mask = trg_tokenizer.encode(raw_text, padding_first=False, add_bos=True, add_eos=True,return_mask=True)\n",
    "print(\"raw text\"+'-'*10)\n",
    "for raw in raw_text:\n",
    "    print(raw)\n",
    "print(\"indices\"+'-'*10)\n",
    "for index in indices:\n",
    "    print(index)\n",
    "print(\"mask\"+'-'*10)\n",
    "for m in mask:\n",
    "    print(m)"
   ],
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "raw text----------\n",
      "['hello', 'world']\n",
      "['tokenize', 'text', 'datas', 'with', 'batch']\n",
      "['this', 'is', 'a', 'test']\n",
      "indices----------\n",
      "tensor([   1,   17, 3222,    3,    0,    0,    0])\n",
      "tensor([   1,    2, 3864,    2,  548,    2,    3])\n",
      "tensor([   1,  121,  236,  107, 1273,    3,    0])\n",
      "mask----------\n",
      "tensor([0, 0, 0, 0, 1, 1, 1])\n",
      "tensor([0, 0, 0, 0, 0, 0, 0])\n",
      "tensor([0, 0, 0, 0, 0, 0, 1])\n"
     ]
    }
   ],
   "execution_count": 24
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-02-05T08:33:04.117677Z",
     "start_time": "2025-02-05T08:33:04.114050Z"
    }
   },
   "cell_type": "code",
   "source": [
    "decode_text = trg_tokenizer.decode(indices.tolist(), remove_bos=False, remove_eos=False, remove_pad=False)\n",
    "\n",
    "print(\"decode text\"+'-'*10)\n",
    "for decode in decode_text:\n",
    "    print(decode)"
   ],
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "decode text----------\n",
      "[BOS] hello world [EOS] [PAD] [PAD] [PAD]\n",
      "[BOS] [UNK] text [UNK] with [UNK] [EOS]\n",
      "[BOS] this is a test [EOS] [PAD]\n"
     ]
    }
   ],
   "execution_count": 25
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "S8BDjaa1Jzbc"
   },
   "source": [
    "### DataLoader"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {
    "id": "sPwlGzn8Jzbc",
    "ExecuteTime": {
     "end_time": "2024-08-01T01:43:37.581540600Z",
     "start_time": "2024-08-01T01:43:37.573524800Z"
    }
   },
   "outputs": [],
   "source": [
    "def collate_fct(batch):\n",
    "    src_words = [pair[0].split() for pair in batch]\n",
    "    trg_words = [pair[1].split() for pair in batch]\n",
    "\n",
    "    # [PAD] [BOS] src [EOS]\n",
    "    encoder_inputs, encoder_inputs_mask = src_tokenizer.encode(\n",
    "        src_words, padding_first=True, add_bos=True, add_eos=True, return_mask=True\n",
    "        )\n",
    "\n",
    "    # [BOS] trg [PAD]\n",
    "    decoder_inputs = trg_tokenizer.encode(\n",
    "        trg_words, padding_first=False, add_bos=True, add_eos=False, return_mask=False,\n",
    "        )\n",
    "\n",
    "    # trg [EOS] [PAD]\n",
    "    decoder_labels, decoder_labels_mask = trg_tokenizer.encode(\n",
    "        trg_words, padding_first=False, add_bos=False, add_eos=True, return_mask=True\n",
    "        )\n",
    "\n",
    "    return {\n",
    "        \"encoder_inputs\": encoder_inputs.to(device=device),\n",
    "        \"encoder_inputs_mask\": encoder_inputs_mask.to(device=device),\n",
    "        \"decoder_inputs\": decoder_inputs.to(device=device),\n",
    "        \"decoder_labels\": decoder_labels.to(device=device),\n",
    "        \"decoder_labels_mask\": decoder_labels_mask.to(device=device),\n",
    "    } #当返回的数据较多时，用dict返回比较合理\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "_JsuutYAJzbc",
    "outputId": "fd68e596-ed01-4bae-d731-c27f5a758a6c",
    "ExecuteTime": {
     "end_time": "2024-08-01T01:43:37.647635800Z",
     "start_time": "2024-08-01T01:43:37.580542500Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "encoder_inputs\n",
      "tensor([[   0,    1,   55,   67, 1056,  306,   50,    5,    3],\n",
      "        [   1,   92, 5604,   50, 2622,  489, 3758,    5,    3]])\n",
      "encoder_inputs_mask\n",
      "tensor([[1, 0, 0, 0, 0, 0, 0, 0, 0],\n",
      "        [0, 0, 0, 0, 0, 0, 0, 0, 0]])\n",
      "decoder_inputs\n",
      "tensor([[   1,   17,   32,  516,   30, 1088, 1577,    5,    0],\n",
      "        [   1,   47, 2976,  689, 5400, 2238,  634,   29,    5]])\n",
      "decoder_labels\n",
      "tensor([[  17,   32,  516,   30, 1088, 1577,    5,    3,    0],\n",
      "        [  47, 2976,  689, 5400, 2238,  634,   29,    5,    3]])\n",
      "decoder_labels_mask\n",
      "tensor([[0, 0, 0, 0, 0, 0, 0, 0, 1],\n",
      "        [0, 0, 0, 0, 0, 0, 0, 0, 0]])\n"
     ]
    }
   ],
   "source": [
    "sample_dl = DataLoader(train_ds, batch_size=2, shuffle=True, collate_fn=collate_fct)\n",
    "\n",
    "for batch in sample_dl:\n",
    "    for key, value in batch.items():\n",
    "        print(key)\n",
    "        print(value)\n",
    "    break"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "K9JaKLR7Jzbc"
   },
   "source": [
    "## 定义模型"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {
    "id": "CGxzT605Jzbd",
    "ExecuteTime": {
     "end_time": "2024-08-01T01:43:37.663622200Z",
     "start_time": "2024-08-01T01:43:37.612142500Z"
    }
   },
   "outputs": [],
   "source": [
    "class Encoder(nn.Module):\n",
    "    def __init__(\n",
    "        self,\n",
    "        vocab_size,\n",
    "        embedding_dim=256,\n",
    "        hidden_dim=1024,\n",
    "        num_layers=1,\n",
    "        ):\n",
    "        super().__init__()\n",
    "        self.embedding = nn.Embedding(vocab_size, embedding_dim)\n",
    "        self.gru = nn.GRU(embedding_dim, hidden_dim, num_layers=num_layers, batch_first=True)\n",
    "\n",
    "    def forward(self, encoder_inputs):\n",
    "        # encoder_inputs.shape = [batch size, sequence length]\n",
    "        # bs, seq_len = encoder_inputs.shape\n",
    "        embeds = self.embedding(encoder_inputs)\n",
    "        # embeds.shape = [batch size, sequence length, embedding_dim]->[batch size, sequence length, hidden_dim]\n",
    "        seq_output, hidden = self.gru(embeds)\n",
    "        # seq_output.shape = [batch size, sequence length, hidden_dim]，hidden.shape [ num_layers, batch size, hidden_dim]\n",
    "        return seq_output, hidden"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "torch.Size([2, 50, 1024])\n",
      "torch.Size([4, 2, 1024])\n",
      "tensor([[-0.0413,  0.0018, -0.0231,  ...,  0.0445, -0.0404, -0.0172],\n",
      "        [-0.0196,  0.0115,  0.0084,  ...,  0.0178, -0.0344, -0.0135]],\n",
      "       grad_fn=<SliceBackward0>)\n",
      "tensor([[-0.0413,  0.0018, -0.0231,  ...,  0.0445, -0.0404, -0.0172],\n",
      "        [-0.0196,  0.0115,  0.0084,  ...,  0.0178, -0.0344, -0.0135]],\n",
      "       grad_fn=<SliceBackward0>)\n"
     ]
    }
   ],
   "source": [
    "#把上面的Encoder写一个例子，看看输出的shape\n",
    "encoder = Encoder(vocab_size=100, embedding_dim=256, hidden_dim=1024, num_layers=4)\n",
    "encoder_inputs = torch.randint(0, 100, (2, 50))\n",
    "encoder_outputs, hidden = encoder(encoder_inputs)\n",
    "print(encoder_outputs.shape)\n",
    "print(hidden.shape)\n",
    "print(encoder_outputs[:,-1,:])\n",
    "print(hidden[-1,:,:]) #取最后一层的hidden"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2024-08-01T02:19:55.960154200Z",
     "start_time": "2024-08-01T02:19:55.426284200Z"
    }
   }
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "outputs": [
    {
     "data": {
      "text/plain": "torch.Size([2, 1, 1024])"
     },
     "execution_count": 13,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "query1 = torch.randn(2, 1024)\n",
    "query1.unsqueeze(1).shape #增加维度"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2024-05-06T01:57:05.054653Z",
     "start_time": "2024-05-06T01:57:04.982694100Z"
    }
   }
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {
    "id": "pTQ6Mz1OJzbd",
    "ExecuteTime": {
     "end_time": "2024-08-01T02:19:58.695774900Z",
     "start_time": "2024-08-01T02:19:58.676428200Z"
    }
   },
   "outputs": [],
   "source": [
    "class BahdanauAttention(nn.Module):\n",
    "    def __init__(self, hidden_dim=1024):\n",
    "        super().__init__()\n",
    "        self.Wk = nn.Linear(hidden_dim, hidden_dim) #对keys做运算，encoder的输出EO\n",
    "        self.Wq = nn.Linear(hidden_dim, hidden_dim) #对query做运算，decoder的隐藏状态\n",
    "        self.V = nn.Linear(hidden_dim, 1)\n",
    "\n",
    "    def forward(self, query, keys, values, attn_mask=None):\n",
    "        \"\"\"\n",
    "        正向传播\n",
    "        :param query: hidden state，是decoder的隐藏状态，shape = [batch size, hidden_dim]\n",
    "        :param keys: EO  [batch size, sequence length, hidden_dim]\n",
    "        :param values: EO  [batch size, sequence length, hidden_dim]\n",
    "        :param attn_mask:[batch size, sequence length]\n",
    "        :return:\n",
    "        \"\"\"\n",
    "        # query.shape = [batch size, hidden_dim] -->通过unsqueeze(-2)增加维度 [batch size, 1, hidden_dim]\n",
    "        # keys.shape = [batch size, sequence length, hidden_dim]\n",
    "        # values.shape = [batch size, sequence length, hidden_dim]\n",
    "        scores = self.V(F.tanh(self.Wk(keys) + self.Wq(query.unsqueeze(-2)))) #unsqueeze(-2)增加维度\n",
    "        # score.shape = [batch size, sequence length, 1]\n",
    "        if attn_mask is not None: #这个mask是encoder_inputs_mask，用来mask掉padding的部分,让padding部分socres为0\n",
    "            # attn_mask is a matrix of 0/1 element,\n",
    "            # 1 means to mask logits while 0 means do nothing\n",
    "            # here we add -inf to the element while mask == 1\n",
    "            attn_mask = (attn_mask.unsqueeze(-1)) * -1e16 #在最后增加一个维度，[batch size, sequence length] --> [batch size, sequence length, 1]\n",
    "            scores += attn_mask\n",
    "        scores = F.softmax(scores, dim=-2) #对每一个词的score做softmax\n",
    "        # score.shape = [batch size, sequence length, 1]\n",
    "        context_vector = torch.mul(scores, values).sum(dim=-2) #对每一个词的score和对应的value做乘法，然后在seq_len维度上求和，得到context_vector\n",
    "        # context_vector.shape = [batch size, hidden_dim]\n",
    "        #socres用于最后的画图\n",
    "        return context_vector, scores\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "torch.Size([2, 2])\n"
     ]
    }
   ],
   "source": [
    "#tensor矩阵相乘\n",
    "a = torch.randn(2, 3)\n",
    "b = torch.randn(3, 2)\n",
    "c = torch.mm(a, b) #增加维度\n",
    "print(c.shape)"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2024-05-06T01:57:05.161598600Z",
     "start_time": "2024-05-06T01:57:05.041662700Z"
    }
   }
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "torch.Size([2, 1024])\n",
      "torch.Size([2, 50, 1])\n"
     ]
    }
   ],
   "source": [
    "#把上面的BahdanauAttention写一个例子，看看输出的shape\n",
    "attention = BahdanauAttention(hidden_dim=1024)\n",
    "query = torch.randn(2, 1024) #Decoder的隐藏状态\n",
    "keys = torch.randn(2, 50, 1024) #EO\n",
    "values = torch.randn(2, 50, 1024) #EO\n",
    "attn_mask = torch.randint(0, 2, (2, 50))\n",
    "context_vector, scores = attention(query, keys, values, attn_mask)\n",
    "print(context_vector.shape)\n",
    "print(scores.shape)"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2024-08-01T02:49:32.095682500Z",
     "start_time": "2024-08-01T02:49:32.051271600Z"
    }
   }
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {
    "id": "6W5FeRRrJzbd",
    "ExecuteTime": {
     "end_time": "2024-08-01T03:02:48.940488500Z",
     "start_time": "2024-08-01T03:02:48.937601400Z"
    }
   },
   "outputs": [],
   "source": [
    "class Decoder(nn.Module):\n",
    "    def __init__(\n",
    "        self,\n",
    "        vocab_size,\n",
    "        embedding_dim=256,\n",
    "        hidden_dim=1024,\n",
    "        num_layers=1,\n",
    "        ):\n",
    "        super(Decoder, self).__init__()\n",
    "        self.embedding = nn.Embedding(vocab_size, embedding_dim)\n",
    "        self.gru = nn.GRU(embedding_dim + hidden_dim, hidden_dim, num_layers=num_layers, batch_first=True)\n",
    "        self.fc = nn.Linear(hidden_dim, vocab_size) #最后分类\n",
    "        self.dropout = nn.Dropout(0.6)\n",
    "        self.attention = BahdanauAttention(hidden_dim) #注意力得到的context_vector\n",
    "\n",
    "    def forward(self, decoder_input, hidden, encoder_outputs, attn_mask=None):\n",
    "        #attn_mask是encoder_inputs_mask\n",
    "        # decoder_input.shape = [batch size, 1]\n",
    "        assert len(decoder_input.shape) == 2 and decoder_input.shape[-1] == 1, f\"decoder_input.shape = {decoder_input.shape}\"\n",
    "        # hidden.shape = [batch size, hidden_dim]，decoder_hidden,而第一次使用的是encoder的hidden\n",
    "        assert len(hidden.shape) == 2, f\"hidden.shape = {hidden.shape}\"\n",
    "        # encoder_outputs.shape = [batch size, sequence length, hidden_dim]\n",
    "        assert len(encoder_outputs.shape) == 3, f\"encoder_outputs.shape = {encoder_outputs.shape}\"\n",
    "\n",
    "        context_vector, attention_score = self.attention(\n",
    "            query=hidden, keys=encoder_outputs, values=encoder_outputs, attn_mask=attn_mask)\n",
    "        # context_vector.shape = [batch size, hidden_dim]\n",
    "        embeds = self.embedding(decoder_input)\n",
    "        # embeds.shape = [batch size, 1, embedding_dim]\n",
    "        embeds = torch.cat([context_vector.unsqueeze(-2), embeds], dim=-1)\n",
    "        # embeds.shape = [batch size, 1, embedding_dim + hidden_dim]\n",
    "        seq_output, hidden = self.gru(embeds)\n",
    "        # seq_output.shape = [batch size, 1, hidden_dim]\n",
    "        logits = self.fc(self.dropout(seq_output))\n",
    "        # logits.shape = [batch size, 1, vocab size]，attention_score = [batch size, sequence length, 1]\n",
    "        return logits, hidden, attention_score\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {
    "id": "FG-Pid9cJzbd",
    "ExecuteTime": {
     "end_time": "2024-08-01T03:26:47.631513900Z",
     "start_time": "2024-08-01T03:26:47.613513600Z"
    }
   },
   "outputs": [],
   "source": [
    "class Sequence2Sequence(nn.Module):\n",
    "    def __init__(\n",
    "        self,\n",
    "        src_vocab_size, #输入词典大小\n",
    "        trg_vocab_size, #输出词典大小\n",
    "        encoder_embedding_dim=256,\n",
    "        encoder_hidden_dim=1024,\n",
    "        encoder_num_layers=1,\n",
    "        decoder_embedding_dim=256,\n",
    "        decoder_hidden_dim=1024,\n",
    "        decoder_num_layers=1,\n",
    "        bos_idx=1,\n",
    "        eos_idx=3,\n",
    "        max_length=512,\n",
    "        ):\n",
    "        super(Sequence2Sequence, self).__init__()\n",
    "        self.bos_idx = bos_idx\n",
    "        self.eos_idx = eos_idx\n",
    "        self.max_length = max_length\n",
    "        self.encoder = Encoder(\n",
    "            src_vocab_size,\n",
    "            embedding_dim=encoder_embedding_dim,\n",
    "            hidden_dim=encoder_hidden_dim,\n",
    "            num_layers=encoder_num_layers,\n",
    "            )\n",
    "        self.decoder = Decoder(\n",
    "            trg_vocab_size,\n",
    "            embedding_dim=decoder_embedding_dim,\n",
    "            hidden_dim=decoder_hidden_dim,\n",
    "            num_layers=decoder_num_layers,\n",
    "            )\n",
    "\n",
    "    def forward(self, *, encoder_inputs, decoder_inputs, attn_mask=None):\n",
    "        # encoding\n",
    "        encoder_outputs, hidden = self.encoder(encoder_inputs)\n",
    "        # decoding with teacher forcing\n",
    "        bs, seq_len = decoder_inputs.shape\n",
    "        logits_list = []\n",
    "        scores_list = []\n",
    "        for i in range(seq_len):#串行训练\n",
    "            # 每次迭代生成一个时间步的预测，存储在 logits_list 中，并且记录注意力分数（如果有的话）在 scores_list 中，最后将预测的logits和注意力分数拼接并返回。\n",
    "            logits, hidden, score = self.decoder(\n",
    "                decoder_inputs[:, i:i+1],\n",
    "                hidden[-1], #取最后一层的hidden\n",
    "                encoder_outputs,\n",
    "                attn_mask=attn_mask\n",
    "                )\n",
    "            logits_list.append(logits) #记录预测的logits，用于计算损失\n",
    "            scores_list.append(score) #记录注意力分数,用于画图\n",
    "\n",
    "        return torch.cat(logits_list, dim=-2), torch.cat(scores_list, dim=-1)\n",
    "\n",
    "    @torch.no_grad() #不计算梯度\n",
    "    def infer(self, encoder_input, attn_mask=None):\n",
    "        #infer用于预测\n",
    "        # encoder_input.shape = [1, sequence length]\n",
    "        # encoding\n",
    "        encoder_outputs, hidden = self.encoder(encoder_input)\n",
    "\n",
    "        # decoding，[[1]]\n",
    "        decoder_input = torch.Tensor([self.bos_idx]).reshape(1, 1).to(dtype=torch.int64) #shape为[1,1]，内容为开始标记\n",
    "        decoder_pred = None\n",
    "        pred_list = [] #预测序列\n",
    "        score_list = []\n",
    "        # 从开始标记 bos_idx 开始，迭代地生成序列，直到生成结束标记 eos_idx 或达到最大长度 max_length。\n",
    "        for _ in range(self.max_length):\n",
    "            logits, hidden, score = self.decoder(\n",
    "                decoder_input,\n",
    "                hidden[-1],\n",
    "                encoder_outputs,\n",
    "                attn_mask=attn_mask\n",
    "                )\n",
    "            # using greedy search\n",
    "            decoder_pred = logits.argmax(dim=-1)\n",
    "            decoder_input = decoder_pred\n",
    "            pred_list.append(decoder_pred.reshape(-1).item()) #decoder_pred从(1,1)变为（1）标量\n",
    "            score_list.append(score) #记录注意力分数,用于画图\n",
    "\n",
    "            # stop at eos token\n",
    "            if decoder_pred == self.eos_idx:\n",
    "                break\n",
    "\n",
    "        # return\n",
    "        return pred_list, torch.cat(score_list, dim=-1)\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "zE-vNp-xJzbe"
   },
   "source": [
    "## 训练"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "o55JWSvhJzbe"
   },
   "source": [
    "### 损失函数"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {
    "id": "c_Mmw5GAJzbe",
    "ExecuteTime": {
     "end_time": "2024-08-01T03:38:58.545747900Z",
     "start_time": "2024-08-01T03:38:58.543749300Z"
    }
   },
   "outputs": [],
   "source": [
    "def cross_entropy_with_padding(logits, labels, padding_mask=None):\n",
    "    # logits.shape = [batch size, sequence length, num of classes]\n",
    "    # labels.shape = [batch size, sequence length]\n",
    "    # padding_mask.shape = [batch size, sequence length]\n",
    "    bs, seq_len, nc = logits.shape\n",
    "    loss = F.cross_entropy(logits.reshape(bs * seq_len, nc), labels.reshape(-1), reduce=False) #reduce=False表示不对batch求平均\n",
    "    if padding_mask is None:#如果没有padding_mask，就直接求平均\n",
    "        loss = loss.mean()\n",
    "    else:\n",
    "        # 如果提供了 padding_mask，则将填充部分的损失去除后计算有效损失的均值。首先，通过将 padding_mask reshape 成一维张量，并取 1 减去得到填充掩码。这样填充部分的掩码值变为 1，非填充部分变为 0。将损失张量与填充掩码相乘，这样填充部分的损失就会变为 0。然后，计算非填充部分的损失和（sum）以及非填充部分的掩码数量（sum）作为有效损失的均值计算。(因为上面我们设计的mask的token是0，所以这里是1-padding_mask)\n",
    "        padding_mask = 1 - padding_mask.reshape(-1) #将padding_mask reshape成一维张量，mask部分为0，非mask部分为1\n",
    "        loss = torch.mul(loss, padding_mask).sum() / padding_mask.sum()\n",
    "\n",
    "    return loss\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "ITY9VUiiJzbe"
   },
   "source": [
    "### Callback"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {
    "id": "qez1fjOPJzbe",
    "ExecuteTime": {
     "end_time": "2024-08-01T06:32:47.905030900Z",
     "start_time": "2024-08-01T06:32:37.847839900Z"
    }
   },
   "outputs": [],
   "source": [
    "from torch.utils.tensorboard import SummaryWriter\n",
    "\n",
    "\n",
    "class TensorBoardCallback:\n",
    "    def __init__(self, log_dir, flush_secs=10):\n",
    "        \"\"\"\n",
    "        Args:\n",
    "            log_dir (str): dir to write log.\n",
    "            flush_secs (int, optional): write to dsk each flush_secs seconds. Defaults to 10.\n",
    "        \"\"\"\n",
    "        self.writer = SummaryWriter(log_dir=log_dir, flush_secs=flush_secs)\n",
    "\n",
    "    def draw_model(self, model, input_shape):\n",
    "        self.writer.add_graph(model, input_to_model=torch.randn(input_shape))\n",
    "\n",
    "    def add_loss_scalars(self, step, loss, val_loss):\n",
    "        self.writer.add_scalars(\n",
    "            main_tag=\"training/loss\",\n",
    "            tag_scalar_dict={\"loss\": loss, \"val_loss\": val_loss},\n",
    "            global_step=step,\n",
    "            )\n",
    "\n",
    "    def add_acc_scalars(self, step, acc, val_acc):\n",
    "        self.writer.add_scalars(\n",
    "            main_tag=\"training/accuracy\",\n",
    "            tag_scalar_dict={\"accuracy\": acc, \"val_accuracy\": val_acc},\n",
    "            global_step=step,\n",
    "        )\n",
    "\n",
    "    def add_lr_scalars(self, step, learning_rate):\n",
    "        self.writer.add_scalars(\n",
    "            main_tag=\"training/learning_rate\",\n",
    "            tag_scalar_dict={\"learning_rate\": learning_rate},\n",
    "            global_step=step,\n",
    "\n",
    "        )\n",
    "\n",
    "    def __call__(self, step, **kwargs):\n",
    "        # add loss\n",
    "        loss = kwargs.pop(\"loss\", None)\n",
    "        val_loss = kwargs.pop(\"val_loss\", None)\n",
    "        if loss is not None and val_loss is not None:\n",
    "            self.add_loss_scalars(step, loss, val_loss)\n",
    "        # add acc\n",
    "        acc = kwargs.pop(\"acc\", None)\n",
    "        val_acc = kwargs.pop(\"val_acc\", None)\n",
    "        if acc is not None and val_acc is not None:\n",
    "            self.add_acc_scalars(step, acc, val_acc)\n",
    "        # add lr\n",
    "        learning_rate = kwargs.pop(\"lr\", None)\n",
    "        if learning_rate is not None:\n",
    "            self.add_lr_scalars(step, learning_rate)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {
    "id": "wXtxS8ukJzbe",
    "ExecuteTime": {
     "end_time": "2024-08-01T06:32:52.240896200Z",
     "start_time": "2024-08-01T06:32:52.234865400Z"
    }
   },
   "outputs": [],
   "source": [
    "class SaveCheckpointsCallback:\n",
    "    def __init__(self, save_dir, save_step=5000, save_best_only=True):\n",
    "        \"\"\"\n",
    "        Save checkpoints each save_epoch epoch.\n",
    "        We save checkpoint by epoch in this implementation.\n",
    "        Usually, training scripts with pytorch evaluating model and save checkpoint by step.\n",
    "\n",
    "        Args:\n",
    "            save_dir (str): dir to save checkpoint\n",
    "            save_epoch (int, optional): the frequency to save checkpoint. Defaults to 1.\n",
    "            save_best_only (bool, optional): If True, only save the best model or save each model at every epoch.\n",
    "        \"\"\"\n",
    "        self.save_dir = save_dir\n",
    "        self.save_step = save_step\n",
    "        self.save_best_only = save_best_only\n",
    "        self.best_metrics = - np.inf\n",
    "\n",
    "        # mkdir\n",
    "        if not os.path.exists(self.save_dir):\n",
    "            os.mkdir(self.save_dir)\n",
    "\n",
    "    def __call__(self, step, state_dict, metric=None):\n",
    "        if step % self.save_step > 0:\n",
    "            return\n",
    "\n",
    "        if self.save_best_only:\n",
    "            assert metric is not None\n",
    "            if metric >= self.best_metrics:\n",
    "                # save checkpoints\n",
    "                torch.save(state_dict, os.path.join(self.save_dir, \"best.ckpt\"))\n",
    "                # update best metrics\n",
    "                self.best_metrics = metric\n",
    "        else:\n",
    "            torch.save(state_dict, os.path.join(self.save_dir, f\"{step}.ckpt\"))\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {
    "id": "lfzfWswRJzbe",
    "ExecuteTime": {
     "end_time": "2024-08-01T06:32:56.655315900Z",
     "start_time": "2024-08-01T06:32:56.645314800Z"
    }
   },
   "outputs": [],
   "source": [
    "class EarlyStopCallback:\n",
    "    def __init__(self, patience=5, min_delta=0.01):\n",
    "        \"\"\"\n",
    "\n",
    "        Args:\n",
    "            patience (int, optional): Number of epochs with no improvement after which training will be stopped.. Defaults to 5.\n",
    "            min_delta (float, optional): Minimum change in the monitored quantity to qualify as an improvement, i.e. an absolute\n",
    "                change of less than min_delta, will count as no improvement. Defaults to 0.01.\n",
    "        \"\"\"\n",
    "        self.patience = patience\n",
    "        self.min_delta = min_delta\n",
    "        self.best_metric = - np.inf\n",
    "        self.counter = 0\n",
    "\n",
    "    def __call__(self, metric):\n",
    "        if metric >= self.best_metric + self.min_delta:\n",
    "            # update best metric\n",
    "            self.best_metric = metric\n",
    "            # reset counter\n",
    "            self.counter = 0\n",
    "        else:\n",
    "            self.counter += 1\n",
    "\n",
    "    @property\n",
    "    def early_stop(self):\n",
    "        return self.counter >= self.patience\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "F2f3S6z7Jzbf"
   },
   "source": [
    "### training & valuating"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {
    "id": "IOlJp26YJzbf",
    "ExecuteTime": {
     "end_time": "2024-05-06T02:18:16.897674100Z",
     "start_time": "2024-05-06T02:18:16.874685800Z"
    }
   },
   "outputs": [],
   "source": [
    "@torch.no_grad()\n",
    "def evaluating(model, dataloader, loss_fct):\n",
    "    loss_list = []\n",
    "    for batch in dataloader:\n",
    "        encoder_inputs = batch[\"encoder_inputs\"]\n",
    "        encoder_inputs_mask = batch[\"encoder_inputs_mask\"]\n",
    "        decoder_inputs = batch[\"decoder_inputs\"]\n",
    "        decoder_labels = batch[\"decoder_labels\"]\n",
    "        decoder_labels_mask = batch[\"decoder_labels_mask\"]\n",
    "\n",
    "        # 前向计算\n",
    "        logits, _ = model(\n",
    "            encoder_inputs=encoder_inputs,\n",
    "            decoder_inputs=decoder_inputs,\n",
    "            attn_mask=encoder_inputs_mask\n",
    "            ) #model就是seq2seq模型\n",
    "        loss = loss_fct(logits, decoder_labels, padding_mask=decoder_labels_mask)         # 验证集损失\n",
    "        loss_list.append(loss.cpu().item())\n",
    "\n",
    "    return np.mean(loss_list)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/",
     "height": 101,
     "referenced_widgets": [
      "267a9f8d838c4649b208914938b1bcff",
      "a9552c62dcb4441fbca47f89e939759d",
      "7dc472c2f73f4443a0e8437074e67476",
      "c46cefacefb54be7ad60ca93855de3ca",
      "9ebbd2d91c9849baaa85cff5b2b048e1",
      "63c6ee4650cb4a938e9f325113e259d1",
      "95d9e57c587f43e6ba5f656f2b2e5c71",
      "863e7ad581894502979884fe0e9e412e",
      "7d21bf5788794ed2b0b4dc4a98a5d2e9",
      "296304e90e43440094ba467cafb20896",
      "c3d8fddae7354c278c8e88291dbcee8d"
     ]
    },
    "id": "brzx2uFHJzbf",
    "outputId": "6c482ef7-5b4c-41e8-954f-6e9d0a034d1b"
   },
   "outputs": [
    {
     "output_type": "display_data",
     "data": {
      "text/plain": [
       "  0%|          | 0/33420 [00:00<?, ?it/s]"
      ],
      "application/vnd.jupyter.widget-view+json": {
       "version_major": 2,
       "version_minor": 0,
       "model_id": "267a9f8d838c4649b208914938b1bcff"
      }
     },
     "metadata": {}
    },
    {
     "output_type": "stream",
     "name": "stderr",
     "text": [
      "/usr/local/lib/python3.10/dist-packages/torch/nn/_reduction.py:42: UserWarning: size_average and reduce args will be deprecated, please use reduction='none' instead.\n",
      "  warnings.warn(warning.format(ret))\n"
     ]
    },
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "Early stop at epoch 4 / global_step 7600\n"
     ]
    }
   ],
   "source": [
    "# 训练\n",
    "def training(\n",
    "    model,\n",
    "    train_loader,\n",
    "    val_loader,\n",
    "    epoch,\n",
    "    loss_fct,\n",
    "    optimizer,\n",
    "    tensorboard_callback=None,\n",
    "    save_ckpt_callback=None,\n",
    "    early_stop_callback=None,\n",
    "    eval_step=500,\n",
    "    ):\n",
    "    record_dict = {\n",
    "        \"train\": [],\n",
    "        \"val\": []\n",
    "    }\n",
    "\n",
    "    global_step = 1\n",
    "    model.train() # 切换到训练模式\n",
    "    with tqdm(total=epoch * len(train_loader)) as pbar:\n",
    "        for epoch_id in range(epoch):\n",
    "            # training\n",
    "            for batch in train_loader:\n",
    "                encoder_inputs = batch[\"encoder_inputs\"]\n",
    "                encoder_inputs_mask = batch[\"encoder_inputs_mask\"]\n",
    "                decoder_inputs = batch[\"decoder_inputs\"]\n",
    "                decoder_labels = batch[\"decoder_labels\"]\n",
    "                decoder_labels_mask = batch[\"decoder_labels_mask\"]\n",
    "\n",
    "                # 梯度清空\n",
    "                optimizer.zero_grad()\n",
    "\n",
    "                # 前向计算\n",
    "                logits, _ = model(\n",
    "                    encoder_inputs=encoder_inputs,\n",
    "                    decoder_inputs=decoder_inputs,\n",
    "                    attn_mask=encoder_inputs_mask\n",
    "                    )\n",
    "                loss = loss_fct(logits, decoder_labels, padding_mask=decoder_labels_mask)\n",
    "\n",
    "                # 梯度回传\n",
    "                loss.backward()\n",
    "\n",
    "                # 调整优化器，包括学习率的变动等\n",
    "                optimizer.step()\n",
    "\n",
    "                loss = loss.cpu().item()\n",
    "                # record\n",
    "                record_dict[\"train\"].append({\n",
    "                    \"loss\": loss, \"step\": global_step\n",
    "                })\n",
    "\n",
    "                # evaluating\n",
    "                if global_step % eval_step == 0:\n",
    "                    model.eval() # 切换到验证模式\n",
    "                    val_loss = evaluating(model, val_loader, loss_fct)\n",
    "                    record_dict[\"val\"].append({\n",
    "                        \"loss\": val_loss, \"step\": global_step\n",
    "                    })\n",
    "                    model.train() # 切换到训练模式\n",
    "\n",
    "                    # 1. 使用 tensorboard 可视化\n",
    "                    if tensorboard_callback is not None:\n",
    "                        tensorboard_callback(\n",
    "                            global_step,\n",
    "                            loss=loss, val_loss=val_loss,\n",
    "                            lr=optimizer.param_groups[0][\"lr\"],\n",
    "                            )\n",
    "\n",
    "                    # 2. 保存模型权重 save model checkpoint\n",
    "                    if save_ckpt_callback is not None:\n",
    "                        save_ckpt_callback(global_step, model.state_dict(), metric=-val_loss)\n",
    "\n",
    "                    # 3. 早停 Early Stop\n",
    "                    if early_stop_callback is not None:\n",
    "                        early_stop_callback(-val_loss)\n",
    "                        if early_stop_callback.early_stop:\n",
    "                            print(f\"Early stop at epoch {epoch_id} / global_step {global_step}\")\n",
    "                            return record_dict\n",
    "\n",
    "                # udate step\n",
    "                global_step += 1\n",
    "                pbar.update(1)\n",
    "            pbar.set_postfix({\"epoch\": epoch_id, \"loss\": loss, \"val_loss\": val_loss}) # 更新进度条\n",
    "\n",
    "    return record_dict\n",
    "\n",
    "\n",
    "epoch = 20\n",
    "batch_size = 64\n",
    "\n",
    "model = Sequence2Sequence(src_vocab_size=len(src_word2idx), trg_vocab_size=len(trg_word2idx))\n",
    "train_dl = DataLoader(train_ds, batch_size=batch_size, shuffle=True, collate_fn=collate_fct)\n",
    "test_dl = DataLoader(test_ds, batch_size=batch_size, shuffle=False, collate_fn=collate_fct)\n",
    "\n",
    "# 1. 定义损失函数 采用交叉熵损失\n",
    "loss_fct = cross_entropy_with_padding\n",
    "# 2. 定义优化器 采用 adam\n",
    "# Optimizers specified in the torch.optim package\n",
    "optimizer = torch.optim.Adam(model.parameters(), lr=0.001)\n",
    "\n",
    "# 1. tensorboard 可视化\n",
    "if not os.path.exists(\"runs\"):\n",
    "    os.mkdir(\"runs\")\n",
    "exp_name = \"translate-seq2seq\"\n",
    "tensorboard_callback = TensorBoardCallback(f\"runs/{exp_name}\")\n",
    "# tensorboard_callback.draw_model(model, [1, MAX_LENGTH])\n",
    "# 2. save best\n",
    "if not os.path.exists(\"checkpoints\"):\n",
    "    os.makedirs(\"checkpoints\")\n",
    "save_ckpt_callback = SaveCheckpointsCallback(\n",
    "    f\"checkpoints/{exp_name}\", save_step=200, save_best_only=True)\n",
    "# 3. early stop\n",
    "early_stop_callback = EarlyStopCallback(patience=5)\n",
    "\n",
    "model = model.to(device)\n",
    "\n",
    "record = training(\n",
    "    model,\n",
    "    train_dl,\n",
    "    test_dl,\n",
    "    epoch,\n",
    "    loss_fct,\n",
    "    optimizer,\n",
    "    tensorboard_callback=tensorboard_callback,\n",
    "    save_ckpt_callback=save_ckpt_callback,\n",
    "    early_stop_callback=early_stop_callback,\n",
    "    eval_step=200\n",
    "    )"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "outputs": [
    {
     "data": {
      "text/plain": "35212249"
     },
     "execution_count": 31,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "#计算模型参数量\n",
    "sum(i[1].numel() for i in model.named_parameters())"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2024-08-01T07:21:09.603023900Z",
     "start_time": "2024-08-01T07:21:09.587018500Z"
    }
   }
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "outputs": [
    {
     "data": {
      "text/plain": "1676.0"
     },
     "execution_count": 27,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "33520/20"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2024-08-01T06:51:34.906600900Z",
     "start_time": "2024-08-01T06:51:34.891495800Z"
    }
   }
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "outputs": [
    {
     "data": {
      "text/plain": "1672.93125"
     },
     "execution_count": 26,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "118964*0.9/64"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2024-08-01T06:50:49.447830800Z",
     "start_time": "2024-08-01T06:50:49.438888Z"
    }
   }
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/",
     "height": 430
    },
    "id": "mAKeaApNJzbf",
    "outputId": "2933f0b5-29b1-47bc-a6dd-63350da513ca"
   },
   "outputs": [
    {
     "output_type": "display_data",
     "data": {
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ],
      "image/png": "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g5CQEI/nVStY6HQ69OzZE1u2bLEfe+yxx7Bz505s3brV7XPctVjEx8fj0qVLFRasulq9sMp++/irw7x23frIaDRi9erVGDp0KLRardzFqXW+VF/WVbl8qb6sqzLl5uYiKiqq0mBRra6QRo0aoX379k7H2rVrh19++cXjc/R6PfR6vctxrVZba78Epf9ybWrz77A+8qX6sq7K5Uv1ZV2Vpar1q9Z00/79++Po0aNOx44dO4amTZtW5zJERESkUNUKFo8//ji2bduGN954A8nJyViwYAG++OILTJo0qbbKV2U3d24kdxGIiIh8XrWCRa9evfDbb79h4cKF6NixI1599VXMmjULY8aMqa3yVVliM+taGoPbNpC5JERERL6rWmMsAODGG2/EjTfeWBtluSK2vUIsXMiCiIhINsrZK6Q0WViYK4iIiGSjmGChsu1uyhYLIiIi2SgoWJTuFcJcQUREJBvFBAvbXiHsCiEiIpKPcoKFvcWCyYKIiEguigkWKs4KISIikp2CgkVpi4XM5SAiIvJligkWBpMFALD9VJbMJSEiIvJdigkWyw+lyV0EIiIin6eYYFFiYicIERGR3BQTLEL8qr06OREREXmZYoLF+AEJcheBiIjI5ykmWIQFaAEAATq1zCUhIiLyXYoJFurShSwKS8wyl4SIiMh3KSZY2NaxAIBiI8MFERGRHBQTLMwOm4ScuVwoY0mIiIh8l2KChXBYc/PrTadkLAkREZHvUkywCPPX2m9fyC2WsSRERES+SzHBItivLFhoVFIFZxIREVFtUUywcBSo52JZREREclBksGB7BRERkTwUGSy4awgREZE8FBks/jnDrdOJiIjkoMhgcT67SO4iEBER+SRFBgsAOHO5QO4iEBER+RzFBoufdp2TuwhEREQ+R7HBgktZEBER1T3FBgtJYrIgIiKqawoOFnKXgIiIyPcoNlj8uDNF7iIQERH5HMUGi9ScYhhMZrmLQURE5FMUFSyuj7U43R//zS6ZSkJEROSbFBUsNOXGVfx9/JI8BSEiIvJRygoWKu4SQkREJCdFBYueUQwWREREclJUsIj0k7sEREREvk1RwYKIiIjkxWBBREREXqO4YNG/RaTcRSAiIvJZigsWzaMC5C4CERGRz1JcsLBwYggREZFsFBcs+jaPcLr/x/4LMpWEiIjI9yguWAxrH+10f9KCf2Qq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\n"
     },
     "metadata": {}
    }
   ],
   "source": [
    "plt.plot([i[\"step\"] for i in record[\"train\"]], [i[\"loss\"] for i in record[\"train\"]], label=\"train\")\n",
    "plt.plot([i[\"step\"] for i in record[\"val\"]], [i[\"loss\"] for i in record[\"val\"]], label=\"val\")\n",
    "plt.grid()\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "UOSROA66Jzbg"
   },
   "source": [
    "## 推理\n",
    "\n",
    "- 翻译项目的评估指标一般是BLEU4，感兴趣的同学自行了解并实现\n",
    "- 接下来进行翻译推理，并作出注意力的热度图"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/",
     "height": 875
    },
    "id": "cX75BqcBJzbg",
    "outputId": "e9dcbb2c-5188-4f2e-a1ac-793fe5f40b19",
    "ExecuteTime": {
     "end_time": "2024-08-01T06:54:16.682669600Z",
     "start_time": "2024-08-01T06:54:14.942826400Z"
    }
   },
   "outputs": [],
   "source": [
    "# load checkpoints,如何上线\n",
    "model = Sequence2Sequence(len(src_word2idx), len(trg_word2idx))\n",
    "model.load_state_dict(torch.load(f\"./best.ckpt\", map_location=\"cpu\"))\n",
    "\n",
    "class Translator:\n",
    "    def __init__(self, model, src_tokenizer, trg_tokenizer):\n",
    "        self.model = model\n",
    "        self.model.eval() # 切换到验证模式\n",
    "        self.src_tokenizer = src_tokenizer\n",
    "        self.trg_tokenizer = trg_tokenizer\n",
    "\n",
    "    def draw_attention_map(self, scores, src_words_list, trg_words_list):\n",
    "        \"\"\"绘制注意力热力图\n",
    "\n",
    "        Args:\n",
    "            - scores (numpy.ndarray): shape = [source sequence length, target sequence length]\n",
    "        \"\"\"\n",
    "        plt.matshow(scores.T, cmap='viridis') # 注意力矩阵,显示注意力分数值\n",
    "        # 获取当前的轴\n",
    "        ax = plt.gca()\n",
    "\n",
    "        # 设置热图中每个单元格的分数的文本\n",
    "        for i in range(scores.shape[0]): #输入\n",
    "            for j in range(scores.shape[1]): #输出\n",
    "                ax.text(j, i, f'{scores[i, j]:.2f}',  # 格式化数字显示\n",
    "                               ha='center', va='center', color='k')\n",
    "\n",
    "        plt.xticks(range(scores.shape[0]), src_words_list)\n",
    "        plt.yticks(range(scores.shape[1]), trg_words_list)\n",
    "        plt.show()\n",
    "\n",
    "    def __call__(self, sentence):\n",
    "        sentence = preprocess_sentence(sentence) # 预处理句子，标点符号处理等\n",
    "        encoder_input, attn_mask = self.src_tokenizer.encode(\n",
    "            [sentence.split()],\n",
    "            padding_first=True,\n",
    "            add_bos=True,\n",
    "            add_eos=True,\n",
    "            return_mask=True,\n",
    "            ) # 对输入进行编码，并返回encode_piadding_mask\n",
    "        encoder_input = torch.Tensor(encoder_input).to(dtype=torch.int64) # 转换成tensor\n",
    "\n",
    "        preds, scores = model.infer(encoder_input=encoder_input, attn_mask=attn_mask) #预测\n",
    "\n",
    "        trg_sentence = self.trg_tokenizer.decode([preds], split=True, remove_eos=False)[0] #通过tokenizer转换成文字\n",
    "\n",
    "        src_decoded = self.src_tokenizer.decode(\n",
    "            encoder_input.tolist(),\n",
    "            split=True,\n",
    "            remove_bos=False,\n",
    "            remove_eos=False\n",
    "            )[0] #对输入编码id进行解码，转换成文字,为了画图\n",
    "\n",
    "        self.draw_attention_map(\n",
    "            scores.squeeze(0).numpy(),\n",
    "            src_decoded, # 注意力图的源句子\n",
    "            trg_sentence # 注意力图的目标句子\n",
    "            )\n",
    "        return \" \".join(trg_sentence[:-1])\n",
    "\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "outputs": [
    {
     "data": {
      "text/plain": "<Figure size 480x480 with 1 Axes>",
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAbkAAAGkCAYAAACsHFttAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjkuMCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy80BEi2AAAACXBIWXMAAA9hAAAPYQGoP6dpAACNqklEQVR4nOzdd3wc9Zn48c9s7ytp1bstufeCC6YYTA81gTQgkAS4Sy5cAqQcuQKkHEl+yaXepR8hBUjohA6mGBtjG/cuS7Z6r9vrzO8P4ZXXWtkmkVZ473m/XvsyO/vM7PfZnZ1nvt/5jlA0TdMQQgghspBushsghBBCTBQpckIIIbKWFDkhhBBZS4qcEEKIrCVFTgghRNaSIieEECJrSZETQgiRtaTICSGEyFpS5IQQQmQtKXLHWL16NYqioCgKO3bsmJQ2NDY2JtuwcOHCcd326tWr+dKXvjSu28xm1dXV/OhHP5rsZiRpmsZtt91GXl7eCfdRRVF46qmnMtq2D5p777133H8/2eyDcOybqDZIkTvOrbfeSkdHB3Pnzk0pOIqiYDKZqK2t5Vvf+hbH/zW0vXv38tGPfpSCggLMZjPTp0/nP/7jPwgGgylxO3fu5Morr6SwsBCLxUJ1dTUf+9jH6O7uBqCiooKOjg7uuuuujOUsTg8vvvgiv/vd73j22WeT+2g6HR0dXHrppRlu3QfLl7/8ZdauXTvZzTitnOjYd+zjnXfeSa4TCoW45557mD59Omazmfz8fK677jr27t2bsu1gMMjdd99NTU0NFouFgoICzj33XJ5++ulkzBNPPMHmzZvHPS/DuG/xNGez2SguLk5Z9uqrrzJnzhwikQjr16/nlltuoaSkhM9+9rMAvPPOO1xwwQVccMEFPPfccxQVFbF582buuusu1q5dy+uvv47JZKKnp4c1a9Zw+eWX89JLL5GTk0NjYyPPPPMMgUAAAL1eT3FxMQ6HI+O5iw+2hoYGSkpKOPPMM9O+Ho1GMZlMo/bf/4scDof8ht6nEx37juXxeACIRCJccMEFNDc384Mf/IDly5fT1dXF/fffz/Lly3n11VdZsWIFAP/4j//Ipk2b+OlPf8rs2bPp6+vj7bffpq+vL7ndvLw8vF7v+CemiaRzzz1X++IXv5h8fuTIEQ3Qtm/fnhK3Zs0a7fOf/7ymaZqmqqo2e/ZsbenSpVoikUiJ27Fjh6Yoivad73xH0zRNe/LJJzWDwaDFYrGTtuWee+7RFixY8Hflc7xzzz1Xu/3227WvfOUrWm5urlZUVKTdc889ydd/8IMfaHPnztVsNptWXl6ufe5zn9N8Pl/KNtavX6+de+65mtVq1XJycrSLLrpI6+/v1zRN0xKJhPaf//mfWnV1tWaxWLT58+drjz766Li1/Qtf+IL2xS9+UcvJydEKCwu1X/3qV5rf79duvvlmzeFwaDU1Ndrzzz+vaZqmPfDAA5rb7U7ZxpNPPqkdv8s/88wz2tKlSzWz2ax5PB7t6quvTr5WVVWlffvb39Y+/elPaw6HQ6uoqNB++ctfpqy/a9cu7bzzztMsFouWl5en3XrrraM+s/Fw0003aUDyUVVVpZ177rnaP/3TP2lf/OIXNY/Ho61evVrTNE0DtCeffDLjbTxVL7zwgrZq1SrN7XZreXl52oc+9CGtvr4++fqmTZu0hQsXamazWVuyZIn2xBNPpPwOT+W7nYjfTzY71WPfsb7zne9oiqJoO3bsSFmeSCS0pUuXarNnz9ZUVdU0TdPcbrf2u9/97qTtOJX3fb9kuPJ9evfdd9m6dSvLly8HYMeOHezbt48777wTnS7141ywYAEXXHABDz/8MADFxcXE43GefPLJUcOdmfLggw9it9vZtGkT3/ve9/jGN77BK6+8AoBOp+MnP/kJe/fu5cEHH+S1117jq1/9anLdHTt2sGbNGmbPns3GjRtZv349V1xxBYlEAoD777+f3//+9/ziF79g79693HHHHdxwww28+eab49b2/Px8Nm/ezO23387nPvc5rrvuOs4880y2bdvGRRddxI033jhqiHgszz33HNdccw2XXXYZ27dvZ+3atSxbtiwl5gc/+AFLly5l+/btfP7zn+dzn/scBw8eBCAQCHDxxReTm5vLli1bePTRR3n11Vf5whe+MC75HuvHP/4x3/jGNygvL6ejo4MtW7YAw5+JyWRiw4YN/OIXvxi1XibbeKoCgQB33nkn7777LmvXrkWn03HNNdegqip+v5/LL7+c2bNns3XrVu69916+/OUvT1pbxdgeeughLrzwQhYsWJCyXKfTcccdd7Bv3z527twJDB/7nn/+eXw+X+YbOm7lMguMdTZjtVo1u92uGY1GDdBuu+22ZMwjjzxywjOPf/7nf9asVmvy+de//nXNYDBoeXl52iWXXKJ973vf0zo7O0etN1E9ubPOOitl2RlnnKF97WtfSxv/6KOPah6PJ/n8E5/4hLZq1aq0seFwWLPZbNrbb7+dsvyzn/2s9olPfOLvbPnotsfjcc1ut2s33nhjcllHR4cGaBs3bjyls/2VK1dq119//ZjvWVVVpd1www3J56qqaoWFhdrPf/5zTdM07Ve/+pWWm5ur+f3+ZMxzzz2n6XS6tN/p3+uHP/yhVlVVlXx+7rnnaosWLRoVxzE9uUy38W/R09OjAdru3bu1X/7yl5rH49FCoVDy9Z///OfSk5tgJzv2Hfs4ymKxpKxzrG3btmmA9uc//1nTNE178803tfLycs1oNGpLly7VvvSlL2nr168ftZ705CbJn//8Z3bs2MHOnTv5y1/+wtNPP82//Mu/pMRop9gz+/a3v01nZye/+MUvmDNnDr/4xS+YOXMmu3fvnoimjzJ//vyU5yUlJclJL6+++ipr1qyhrKwMp9PJjTfeSF9fX7JndLQnl059fT3BYJALL7wweT3E4XDw+9//noaGhnFvu16vx+PxMG/evOSyoqIigGQ+J3OifNK9p6IoFBcXJ7e/f/9+FixYgN1uT8asWrUKVVWTvb2JtmTJkhO+/kFo4/EOHTrEJz7xCaZOnYrL5aK6uhqA5uZm9u/fz/z587FYLMn4lStXTko7xcix79jHsU71uHfOOedw+PBh1q5dy7XXXsvevXs5++yz+eY3vzkBrU4lRe4UVFRUUFtby6xZs7juuuv40pe+xA9+8APC4TDTp08Hhg8m6ezfvz8Zc5TH4+G6667j+9//Pvv376e0tJTvf//7E54HgNFoTHmuKAqqqtLY2Mjll1/O/Pnzefzxx9m6dSv//d//DQxPaACwWq1jbtfv9wPDQ4DH/iD27dvHY489NmFtP3aZoigAqKqKTqcb9QOMxWIpz0+Uz4neU1XV99XuiXRs8TpdXHHFFfT39/PrX/+aTZs2sWnTJmBkPzuZU/luxfg4euw79nHU9OnTT3jcOxpzlNFo5Oyzz+ZrX/saL7/8Mt/4xjf45je/ecrf+99KitzfQK/XE4/HiUajLFy4kJkzZ/LDH/5w1MFv586dvPrqq3ziE58Yc1smk4mamprk7MrJsnXrVlRV5Qc/+AErVqxg+vTptLe3p8TMnz9/zGnZs2fPxmw209zcPOpHUVFRkYkUUhQUFODz+VI+1+PPQk+Uz6mYNWsWO3fuTHmPDRs2oNPpmDFjxt+83fH0QWtjX18fBw8e5N/+7d9Ys2YNs2bNYmBgIKW9u3btIhwOJ5cdO2UdTu27FRPv4x//OK+++mryuttRqqrywx/+kNmzZ4+6Xnes2bNnE4/HU77riSBF7hT09fXR2dlJa2srL7zwAj/+8Y8577zzcLlcKIrCb3/7W/bt28dHPvIRNm/eTHNzM48++ihXXHEFK1euTN6A/eyzz3LDDTfw7LPPUldXx8GDB/n+97/P888/z1VXXTWpOdbW1hKLxfjpT3/K4cOH+cMf/jBqIsPdd9/Nli1b+PznP8+uXbs4cOAAP//5z+nt7cXpdPLlL3+ZO+64gwcffJCGhga2bdvGT3/6Ux588MGM57N8+XJsNhtf//rXaWho4KGHHuJ3v/tdSsw999zDww8/zD333MP+/fvZvXs33/3ud0/5Pa6//nosFgs33XQTe/bs4fXXX+f222/nxhtvTA6dTrYPWhtzc3PxeDz86le/or6+ntdee40777wz+fonP/lJFEXh1ltvZd++fTz//POjRjlO5bs9HfzsZz876XD5ZDt67Dv2cbQo3XHHHSxbtowrrriCRx99lObmZrZs2cJHPvIR9u/fz29/+9vk6Mrq1av55S9/ydatW2lsbOT555/n61//evI4OpGkyJ2CCy64gJKSEqqrq7ntttu47LLL+POf/5x8/cwzz+Sdd95Br9dz6aWXUltby913381NN93EK6+8gtlsBobPXGw2G3fddRcLFy5kxYoV/OUvf+E3v/kNN95442SlBwzPBP2v//ovvvvd7zJ37lz+9Kc/cf/996fETJ8+nZdffpmdO3eybNkyVq5cydNPP43BMHy75Te/+U3+/d//nfvvv59Zs2ZxySWX8NxzzzFlypSM55OXl8cf//hHnn/+eebNm8fDDz/MvffemxKzevVqHn30UZ555hkWLlzI+eef/75uRrXZbLz00kv09/dzxhlncO2117JmzRp+9rOfjXM2f7sPWht1Oh2PPPIIW7duZe7cudxxxx38v//3/5KvOxwO/vrXv7J7924WLVrEv/7rv4468TiV7/Z00NvbO27XqyfK0WPfsY+jf03HYrHw2muv8alPfYqvf/3r1NbWcskll6DX63nnnXeS98gBXHzxxTz44INcdNFFzJo1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"
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": "'it s very cold here .'"
     },
     "execution_count": 29,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "translator = Translator(model.cpu(), src_tokenizer, trg_tokenizer)\n",
    "translator(u'hace mucho frio aqui .')"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2024-08-01T06:54:20.377291800Z",
     "start_time": "2024-08-01T06:54:19.612529200Z"
    }
   }
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "outputs": [
    {
     "data": {
      "text/plain": "<Figure size 560x480 with 1 Axes>",
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAfcAAAHFCAYAAADvx7CBAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguNCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8fJSN1AAAACXBIWXMAAA9hAAAPYQGoP6dpAABzDElEQVR4nO3deXhb5Znw/+/RbluL992xk9jZ94SEBEJCSdi3lqVQSoG29G07b1ug7dtm2il02oEOQwf4daYLnULLlK0tUFq2QgIBspCQxdk3O7HjxEu8S7IsyZKe3x9O5CiWkzixJefk/lzXuYiP7nP03NI559bznEdCU0ophBBCCKEbhmQ3QAghhBBDS4q7EEIIoTNS3IUQQgidkeIuhBBC6IwUdyGEEEJnpLgLIYQQOiPFXQghhNAZKe5CCCGEzkhxF0IIIXRGivtJLF68GE3T0DSNysrKpLShpqYm2oYZM2YkpQ1CnI2VK1eiaRodHR3JbspZe+ihh055Ht59993ceOONCWmPGJyRcE1PVBukuJ/CvffeS0NDA1OmTIkptJqmYbFYKC8v56c//Skn/orvjh07uPXWW8nJycFqtTJu3Dh+9KMf4fP5YuK2bNnC9ddfT25uLjabjbKyMj772c9y5MgRAEpKSmhoaODb3/52wnIeasdet2SdTCK5FixYQENDAy6XK9lNOWvf+c53WLFiRbKbIc7Cya7pxy8ff/xxdJvu7m4efPBBxo0bh9VqJTs7m1tuuYUdO3bE7Nvn87Fs2TLGjh2LzWYjJyeHRYsW8dprr0VjXnnlFdavXz/seZqG/RnOcampqeTn58esW758OZMnTyYQCLBq1Sq+/OUvU1BQwJe+9CUAPv74Y5YsWcKSJUt44403yMvLY/369Xz7299mxYoVvP/++1gsFpqbm7nsssu49tpr+cc//kF6ejo1NTX87W9/o6urCwCj0Uh+fj52uz3huQsxFCwWS79z6Fxlt9vlXDzHneyafrysrCwAAoEAS5Ys4eDBg/z85z9n3rx5NDU18cgjjzBv3jyWL1/OhRdeCMBXv/pV1q1bxy9+8QsmTZpEa2sra9asobW1NbrfzMxM3G73MGcJKDGgRYsWqW9961vRvw8cOKAAtXnz5pi4yy67TH39619XSikViUTUpEmT1Jw5c1Q4HI6Jq6ysVJqmqZ/97GdKKaVeffVVZTKZVE9Pzynb8uCDD6rp06efVT5nKxwOq4cffliVlZUpm82mpk2bpv785z8rpZRqa2tTn/vc51R2dray2WyqvLxcPf3000oppYCYZdGiRUoppdavX6+WLFmisrKylNPpVJdcconauHFjstI7I2f6mpzLFi1apP7v//2/6lvf+pZKT09Xubm56qmnnlJer1fdfffdym63q7Fjx6o333xTKaXU+++/rwDV3t6e3Iafht/85jeqoKCg37l7/fXXq3vuuaffeRgKhdT999+vXC6XyszMVN/97nfVF77wBXXDDTdEY9566y110UUXRWOuueYaVVVVlaCMxPFO95p+vJ/97GdK0zRVWVkZsz4cDqs5c+aoSZMmqUgkopRSyuVyqd///venbMfpPO/ZkmH5s7RhwwY2btzIvHnzAKisrGTnzp088MADGAyxL+/06dNZsmQJL7zwAgD5+fmEQiFeffXVfsP6I9EjjzzCs88+y69//Wt27NjB/fffz+c//3k++OAD/uVf/oWdO3fy1ltvsWvXLn71q1+RnZ0NEB2CWr58OQ0NDbzyyisAeDwe7rrrLlatWsXHH39MRUUFV199NR6PJ2k5DtaZvibnuj/84Q9kZ2ezfv16vvGNb/C1r32NW265hQULFrBp0yYuv/xy7rzzzn63oUa6W265hdbWVt5///3oura2Nt5++23uuOOOfvE///nP+f3vf8/TTz/NqlWraGtr49VXX42J6erq4oEHHmDDhg2sWLECg8HApz/9aSKRyLDnI87e888/z9KlS5k+fXrMeoPBwP3338/OnTvZsmUL0HtNf/PNN0fGNWzYPjbowECf8lJSUlRaWpoym80KUF/5yleiMS+++OJJP5F985vfVCkpKdG///mf/1mZTCaVmZmprrzySvXoo4+qxsbGftslu+fu9/tVamqqWrNmTcz6L33pS+r2229X1113nbrnnnvibnu6n1LD4bByOBzq73//+1A1e1idzWtyLlu0aJG6+OKLo3+HQiGVlpam7rzzzui6hoYGBai1a9eeUz13pZS64YYb1Be/+MXo37/5zW9UYWGhCofD/c7DgoIC9eijj0b/7unpUcXFxTE99xM1NzcrQG3btm04mi9O4lTX9OOXY2w2W8w2x9u0aZMC1EsvvaSUUuqDDz5QxcXFymw2qzlz5qj77rtPrVq1qt920nMfoV566SUqKyvZsmULf/rTn3jttdf4/ve/HxOjTrMn/m//9m80Njby61//msmTJ/PrX/+aCRMmsG3btuFo+hmrqqrC5/OxdOnS6H1Hu93Os88+S3V1NV/72td48cUXmTFjBv/v//0/1qxZc8p9NjU1ce+991JRUYHL5cLpdOL1ejl48GACMjp7w/GanCumTZsW/bfRaCQrK4upU6dG1+Xl5QFEJ4aeS+644w5efvllAoEAAM899xy33XZbv5G4zs5OGhoaoqN2ACaTiTlz5sTE7du3j9tvv50xY8bgdDopKysDOGeO8/PBsWv68cvxTvd6fskll7B//35WrFjBzTffzI4dO1i4cCE/+clPhqHVJycT6s5ASUkJ5eXlAEycOJHq6mr+5V/+hYceeohx48YBsGvXLmbOnNlv2127dkVjjsnKyuKWW27hlltu4eGHH2bmzJk89thj/OEPfxj+ZE6T1+sF4I033qCoqCjmMavVSklJCbW1tbz55pu8++67XHbZZfzTP/0Tjz322ID7vOuuu2htbeXJJ5+ktLQUq9XK/PnzCQaDw5rLUBmO1+RcYTabY/7WNC1mnaZpAOfk0PN1112HUoo33niDCy64gI8++ojHH3/8rPZXWlrKb3/7WwoLC4lEIkyZMuWcOc7PB8df0080btw4du3aFfexY+uPv6abzWYWLlzIwoUL+d73vsdPf/pT/vVf/5Xvfe97WCyWoW/8AKTnPgSMRiOhUIhgMMiMGTOYMGECjz/+eL8L25YtW1i+fDm33377gPuyWCyMHTs2Olt+pJg0aRJWq5WDBw9SXl4es5SUlACQk5PDXXfdxR//+EeeeOIJnnrqKYDoAR0Oh2P2uXr1ar75zW9y9dVXM3nyZKxWKy0tLYlN7CyczWsiRi6bzcZnPvMZnnvuOV544QXGjx/PrFmz+sW5XC4KCgpYt25ddF0oFGLjxo3Rv1tbW9mzZw8//OEPueyyy5g4cSLt7e0JyUMMjdtuu43ly5dH76sfE4lEePzxx5k0aVK/+/HHmzRpEqFQCL/fP9xNjSE99zPQ2tpKY2MjoVCIbdu28eSTT3LppZfidDoB+N3vfsfSpUu56aabWLZsGfn5+axbt45vf/vbzJ8/n/vuuw+A119/nRdffJHbbruNcePGoZTi73//O2+++SbPPPNMEjPsz+Fw8J3vfIf777+fSCTCxRdfTGdnJ6tXr8bpdFJdXc3s2bOjXxF8/fXXmThxIgC5ubmkpKTw9ttvU1xcjM1mw+VyUVFRwf/+7/8yZ84c3G433/3ud0lJSUlypqfvbF4TMbLdcccdXHvttezYsYPPf/7zA8Z961vf4mc/+xkVFRVMmDCB//zP/4z5sZ6MjAyysrJ46qmnKCgo4ODBg/1u4Z2r/uu//otXX31VF9/7P3ZNP156ejo2m43777+f1157jeuuuy7mq3APP/wwu3btYvny5dGRqsWLF3P77bczZ84csrKy2LlzJ//8z/8cUx8SZtju5uvAQJMvji1Go1EVFxere++9Vx05ciRm261bt6qbbrpJZWZmKrPZrMaOHat++MMfqq6urmhMdXW1uvfee9W4ceNUSkqKSk9PVxdccIF65pln+rUl2RPqlOr9mt8TTzyhxo8fr8xms8rJyVFXXHGF+uCDD9RPfvITNXHiRJWSkqIyMzPVDTfcoPbv3x/d9re//a0qKSlRBoMh+lW4TZs2qTlz5iibzaYqKirUn//8Z1VaWqoef/zx5CR4Bs7mNTlXnXheKKXivm+AevXVV8+5CXVK9U7uLCgoUICqrq6Orj/xPOzp6VHf+ta3lNPpVOnp6eqBBx7o91W4d999V02cOFFZrVY1bdo0tXLlyuhrcy578MEHVWlpabKbMSinuqYfv7zwwgvRuK6uLvWDH/xAlZeXK7PZrDIzM9VNN93Ub1Lkww8/rObPn68yMzOVzWZTY8aMUd/85jdVS0tLTFwiJtRpSp0D38FKksWLFzNjxgyeeOKJZDeFhx56iL/+9a/yK29CCHGGRso1vaamhtGjR7N58+Zh+1lxued+Cr/85S+x2+1Jm71+8OBB7HY7Dz/8cFKeXwgh9CTZ1/Srrrqq36/hDQfpuZ/E4cOH6e7uBmDUqFEJnel4TCgUoqamBuibgS2EEGLwRsI1PVFtkOIuhBBC6IwMywshhBA6I8VdCCGE0Bkp7kIIIYTOSHFPgEAgwEMPPRT9rerzheQteZ8PJG/JeySSCXUJ4Ha7cblcdHZ2Jv5XipJI8pa8zweSt+Q9EknPXQghhNAZKe5CCCGEzpw3/+OYSCRCfX09Docj+iP/ieJ2u2P+e76QvCXv84HkLXknilIKj8dDYWEhBsPJ++bnzT33Q4cOya+7CSGEOOfV1dVRXFx80pjzpufucDgAWFz8ZUyGxP/kYDI1LSlKdhOSwj32vPjc2k/F/zQluwnJcX70U/rrHtmztodLuDAr2U1IuFA4wEdbH4/Ws5M5b4r7saF4k8GCyWBNcmsSy2ixJbsJSWGwnZ8X+/Pt+I46X4u74fzMWzOep8c5nNatZZlQJ4QQQuiMFHchhBBCZ6S4CyGEEDojxV0IIYTQGSnuQgghhM5IcRdCCCF0Roq7EEIIoTNS3IUQQgidkeIuhBBC6IwUdyGEEEJnpLgLIYQQOiPFXQghhNAZKe5CCCGEzkhxF0IIIXRGirsQQgihM1LchRBCCJ2R4i6EEELojBR3IYQQQmekuAshhBA6I8VdCCGE0Bkp7kIIIYTOSHEXQgghdEaKuxBCCKEzpmQ98cqVK7n00ktpb28nPT09bsxDDz3EX//6VyorKxPattNR667kQOdGguEuHJYcJmZdSro1f8D4xq697GtfQ3fITao5nfEZC8lJHR19/O2ax+NuNz5jIaNdc4a8/WeqefsqjlSuJNTtISWrkKKLPk1a3qgB4zuqt9DwyVsEPe1YXdkUzrsWZ+nEuLF1H/6F1p1rKVxwA7nTLhmuFM6Ie9VqOleuJOzxYCksIOvTn8Y6auC8u7Zsof2ttwm1t2PKzibz2mtIndiXd9fWbbjXriV46BARn4/CB+7HWlSUiFQGpbZzMwc6Puk7zrMvI91WMGB8o3cP+9pW0x3qJNWcwfjMS8hJGxN9XClFVftqDrm30RMJkGErZFL2UtIsGYlI57TVdm7mQOeG487vT5067/bVvee3KYPxWQvJST0x7zUc8hyf9xLSzCMs765tHOjaTDDsw2HOYqLzEtIteQPGN3ZXsc+zju6wh1STi/GO+eTYyqKPK6Wo8q7nkG9nb96WAia5FpFmSh/+ZM5zCeu5L168mPvuu29Q23znO99hxYoVw9Ogs9DQtYfdbR9Snn4hCwrvwGHJZkPTKwTCvrjx7f56tjS/SbFjCgsK7yAvtZxNR/6GJ9gSjbm0+Csxy5SsywHISy1PSE6no71qM/Vr/kb+nMsZf9P9pGQVsv+Np+jp9sSN72o8QM3yP5I1YR7jb34AV9kUDvzjGbrbGvrFdhzYRldTLeZU53CnMWjezZW0/u1vpF++lML778NSWEjjU78l7Imft/9ADUf++Bz2eXMpfOB+0qZMoemZ3xNs6Ms7EgxiG11G5jXXJCqNQWvw7mZ3y0rKM+azoPhOHJZcNjT8hUCoK258u/8wW5pe7z3Oi79AXlo5mxr/iifQHI050LGe2s7NTMpZyvyiOzBqZjY0/IVwJJSotE6pwbub3a0f9OZddCcOSw4bGl8+yfl9mC1H3qDYMZUFRXcezfu1mPP7QOcn1Lo3Myl7CfMLP3c075dHVt7d+9jtXkW5/QIWZN+Kw5TNhra/D5x3sIEtHe9QnDqRBdm3kmcbw6b2t/D0tEZjDnRtprZrK5Nci5iffTNGzcSGtr8TViMnb70a0cPydrudrKysZDejn5rOTZQ4plDsmIzdksXkrCUYNROHPdvjxte6N5OdUsZo1xzsliwqMhbgtORy0F0ZjbGa0mKWI75qMm0lpJrTE5PUaWje+iFZEy8ka8JcbJn5FF9yEwaTmbbd6+PHb/sIZ8l4cmdcii0jj4K5V5GSXUTL9tUxcUFvJ4dXvUrpZXeAwZiIVAbF/eEHOC6ch2PuXCz5+WTddBOa2Yxn/Sfx4z/6iJTx40m/9FIseXlkXHUl1qIi3Kv78nbMmU3G5ZdjG1eRqDQGraZjAyXOqRQ7p2K3ZDM5ZylGzTzwcd6xiezU0YzOmNt7nGdejNOaFz3OlVLUdm5ibMaF5KWV47DmMDX3agJhL0e6qhKY2cnVdG7szdsxpff8zj6W97a48bWdR/NOv+Bo3hf15t25GTgu7/R5x+V9VW/evhGUd1clJamTKU6diN2cyWTX4t7rWveuuPG1XVvJto5itH0WdnMmFY55OM05HPT1vk5KKWq7tjDWPoc82xgc5mympi8hEO7iiP9AIlM7LyWkuN9999188MEHPPnkk2iahqZp1NTUALBx40bmzJlDamoqCxYsYM+ePdHtHnroIWbMmBH9e+XKlcydO5e0tDTS09O56KKLqK2tTUQKUREVxh1sIsvWNySraRpZtlF0BPr3SAE6Ag0x8QDZKaUDxgfCXTR3H6DYPmXoGn6WIuEQvuZD2Iv7ipGmGbAXj6OrKf570NVUi714XMw6R8l4uppqon8rFeHge8+TO30xKZkD39ZIFhUKETh0mJSKvjw0g4GUcRUEBjj2/LW1pJxQtFPGjydQk9hj9WxEVBh3oIms1NLoOk3TyEoZRYe/Pu42HYF6slJKY9Zlp5ZF47tDnQTCXTExZqMVl7WAjkD8fSZaNO+UE87vlFF0+Ac4v/0NMfEQe37HzdtwNO8BXstEi6gw7p5msqzF0XWappFlLaYj2Bh3m45gI1nWkph12daSaHx32E0g4ovZp9lgxWXJG3CfYugkpLg/+eSTzJ8/n3vvvZeGhgYaGhooKek9KH7wgx/w85//nA0bNmAymfjiF78Ydx+hUIgbb7yRRYsWsXXrVtauXctXvvIVNE2LGx8IBHC73THLUAiGu1EoLMbUmPVWY+qAw1eBcFec+LQB4w97d2IymEfUkHzY3wUqgjnFEbPenGIn5Is/PB3yeTCn2E+Id8TEH9n8PprBQPbUhUPf6CEQ7uqCSASjIzYPo91B2BP/mAp7PBjtsa+T0WEnNMAw/kjUd5ynxay3mtIIhOMPywdC8Y7z1Gj8sf/GjRlgqD/RBsz7uDxONPD5fRp5D7DPRAtG/L15G05ooyGVQGSA61rEh8WQMmD8sf/232fKgPsUQychE+pcLhcWi4XU1FTy83t7Z7t37wbg3/7t31i0aBEA3//+97nmmmvw+/3YbLaYfbjdbjo7O7n22msZO3YsABMnxp+YBfDII4/w4x//eDjSGXaHPTsoSJuI0ZC0+Y4J4Wuuo3nbR4y/+f4BP6QJIYQYvKTfc582bVr03wUFvbNRjxw50i8uMzOTu+++myuuuILrrruOJ598koaG+MNkAMuWLaOzszO61NXVDUl7LcYUNDSCJ/S6A2Ef1hM+mR9jNabFie+KG9/mP0RXqJ1ix8gZkgcw2tJAM/SbPNfT7cWU6oi7jSnVQU+394R4TzTe23CAULeXHX/8KZW/+S6Vv/kuPd526tf+jR1//OnwJDJIxrQ0MBgIe2LzCHs9GB3xJ/8ZHQ7C3tjXKezxYnLEf51Gor7jPLZnGQh1YT2hV3uM1RTvOPdF44/9N26MKf4+E23AvI/L40QDn9+nkfcA+0w0i8HWm/cJPepAxIfVMMB1zZBKMNI9YPyx//bfZ/eA+xRDJ+nF3Ww2R/99rPcWiUTixj7zzDOsXbuWBQsW8NJLLzFu3Dg+/vjjuLFWqxWn0xmzDAWDZsRpyaPV3/dhQSlFq7+OdGv8r8qkWwto9R+MWdfqPxg3/pBnB05LLk5LzpC0d6gYjCZSc4rxHt4XXadUBO/hfaTllcbdJi2vNCYewHNoL2l5ZQBkjpvN+Fu/zfhbHogu5lQnudMXM/barwxbLoOhmUxYi4vw7zsu70iE7n1VWEvj520rLaV7X2ze3Xv3Yi2LHz8SGTQjTmserb6+41YpRWv3QdJthXG3SbcW0todO6+g1VcbjU8xubAa02JiQpEAnYEG0q3x95lo0by74+U9wPltK4iJB2jtro2e331598VE8x7gtUw0g2bEac6hNXAouk4pRWvgEOmW+HNh0i35MfFATHyK0YnVkBoTE4oE6Qw2DbhPMXQSVtwtFgvhcPis9zNz5kyWLVvGmjVrmDJlCs8///wQtG5wylyzOOTZxmHvDrzBVna0riCseihyTAZga/Pb7GlfFY0vdc6kpbuWA50b8Qbb2Ne+ls5AE6OcM2L2G4oEaPLtHVET6Y6XM+0SWneto23PJ/jbmzj04ctEeoJkjp8LQO17z1O/7o2++KkLcdft5siWlfjbm2j45B90Nx8ie8pFAJhsaaRkFsQsGIyYUp3Y0nOTkmM8zksW4Vm3Ds8nnxBsaqL15VdQwSCOuRcA0Pz8C7S98WZf/MKFdO/eQ+fKlQSbjtD+j38QOHQI50UXRWPCPh+Bw4fpaWoCoOdIM4HDhwkN0dyQoVCWPodDnq0cdm/vPc5b3j16nPcen1ub3mRP64fR+NL0WbT4ajjQ8QneYCv72lbTGWiMHueaplHqmkV1+8cc6arCE2hma9NbWI12ctNGzvySMtfs3vPbc/T8blnem/fR83LrkbfY0/ZRNL7UdSzvDUfzXtN7frtmAsfl3XE072AzW48czXsEzaspS5vBId9ODvt24+1pY4d7JWEVoiil9/bn1o7l7HGvjcaXpk2jJXCQA97NeEPt7POsp7PnCKNSpwJH806bTrV3I0f8B/D0tLK1YzlWYxq5ttFx2yCGTsJu6paVlbFu3Tpqamqw2+0D9s4HcuDAAZ566imuv/56CgsL2bNnD/v27eMLX/jCMLV4YAVp4wmGu9nXvpZA2IfTksOcvE9Hh9i6Qx6g7x5yhq2Q6TlXsbd9DXvbV5NmTmdW7vU4LNkx+23o2oMCCuwTEpjN6cson0nI30XDJ/8g5HOTkl3EmGvuxXx0mD3o6eD4vNPyR1N22edpWP8WDevexOrKYfQV9/QW8XOIfeYMIl1e2v/xD8JuD9aiQvLu/TLGo8PsoY52OG7OgG10Gbmfv4P2t96m7c23MOdkk3fP3VgK+vL2bd9By0svRf9u/uMfAUi/fCkZV1yRoMxOrsA+gWDYx7721QRCPpzWHOYU3BwdQu8OuWPyzrAVMT3vGva2rWJv66re4zz/RhzWvlGo0elzCasetje/QygSIMNWxJyCm0bU/JLevLtj886/KTZvTsg792r2tq9mb9uxvG+IOb9Huy4gHOlhe8u7fXnnf2Zk5Z1SQTDSzT7vut7rmjmbOZnXRm8fdodPuK5ZCpievpS9nnXs9XxMmimdWRlX4TD3fX15dNrM3ve7831CkSAZlgLmZF6HURs5eeuVppRSiXiivXv3ctddd7Flyxa6u7t55plnuOeee2J+oa6yspKZM2dy4MABysrKYn6hrqmpia9+9ausW7eO1tZWCgoKuOuuu3jwwQcxGE49AOF2u3G5XCwZ9XVMBuswZzuyNF5ZfOogHeqsSMihPeKM/+V5+jWjxFzKRp5uf7JbkBThouxTB+lMKBzg/c0/o7Oz85S3mhNW3JNNivv5R4r7eeb8uJT1J8X9vDGY4p70CXVCCCGEGFpS3IUQQgidkeIuhBBC6IwUdyGEEEJnpLgLIYQQOiPFXQghhNAZKe5CCCGEzkhxF0IIIXRGirsQQgihM1LchRBCCJ2R4i6EEELojBR3IYQQQmekuAshhBA6I8VdCCGE0Bkp7kIIIYTOSHEXQgghdEaKuxBCCKEzUtyFEEIInZHiLoQQQuiMFHchhBBCZ6S4CyGEEDojxV0IIYTQGSnuQgghhM5IcRdCCCF0xpTsBiSa8vpQhlCym5FQues6k92EpJj35f3JbkJS1D6RlewmJEWwLCfZTUgK8776ZDchKbS9B5PdhITTVPC0Y6XnLoQQQuiMFHchhBBCZ6S4CyGEEDojxV0IIYTQGSnuQgghhM5IcRdCCCF0Roq7EEIIoTNS3IUQQgidkeIuhBBC6IwUdyGEEEJnpLgLIYQQOiPFXQghhNAZKe5CCCGEzkhxF0IIIXRGirsQQgihM1LchRBCCJ2R4i6EEELojBR3IYQQQmekuAshhBA6I8VdCCGE0Bkp7kIIIYTOSHEXQgghdEaKuxBCCKEzUtyFEEIInZHiLoQQQuiMKdkNOJXFixczY8YMnnjiiWQ3JcbB7h0c6N5CMNKNw5TJhLSLSDfnxo2t8++i3r8Pb7gNAKcph4rUC2Lit3lWUh/YG7NdlrmYOa6rhy2HM3Gw+RNqjqwh2OPFnpLHxOKrcKUVxY31dh+hqmEl7u4G/MFOxhddTmnuhTExbd5aaprW4PE1EAh5mTH6VnLTJyQilUHZ/qc9bPnfnXS3dpNVkcFF372A3CnZA8ZXL69lw6+24Gnw4ipxMu8bMxl1ce/rFA5F+OSXldStrsd92IPFbqFobj7zvjGTtJzURKV0Wmo9Wzjg2Ugw7MNhyWZi+mLSrfkDxjf69rGvcy3dITep5nTGuy4iJ2V09HGlFFXujznk3U6PCpBhKWRSxqWkmTMSkc5pO1T/MQcPrSIY9GK35zNu7LU4HcUDxh9p3s7+2uX4/R2kpGQxdvTlZGeOjz6ulOJA7QrqGzcQCvtxOUcxvvx6UlMGPoaS4WDXNg50VRKM+HCYs5jgWEi6JW/A+EZ/FVWe9XSHPaSaXIxzzCfHWhp9vMlfTZ1vB+6eZnpUgPlZt+I0j6yc9WrE99xfeeUVfvKTnyS7GTEaAtXs7lpLeeps5qd/Bocxi43uNwlEuuPGt/c0UGAdywWua5nnuhGbIY2N7jfxh7ti4rLNJSzO/Hx0me64LBHpnLbG9h3sOfwOY/MXceH4r+BIyWdj9XMEerrixocjPaRYM6govAyLyR4/JhzEkZLHhJKR9SHmeFXv1LD28Y3MvncaN/3xajLHZfDGN96ju80fN75xSzMrfrCK8TeM5abnrqFscTH/+M4HtFV1ABDyh2jZ3casL0/lpj9ezeX/cQmdtW7efmBl4pI6DQ2+vezu+Ihy5zwW5N+Ow5zDhua/Egj74sa3B+rZ0voWxWmTWZD/OfJSxrKp5XU8wZZozAHPRmo9lUzK/BTzcz+LUTOzofmvhFUoUWmdUlPzNvbtf4uyUZdywcyvY0/Lp3L77wkGvXHjO90H2bH7TxTkz+aCWV8nJ2si23Y+j7erKRpz8NBHHKr/mPEVNzBnxlcxGixUbv8D4UhPotI6pYbufez2rKbcPof52bfgMGWzsf31gd/vYANbO96lKHUi87NvIdc6ms3tb+HpaY3GhFWIdEsB4xzzE5WGOGrEF/fMzEwcDkeymxGjtnsrxbYJFNnGYzdlMMm+EKNm4rB/T9z4aY5PMSplMk5TNnZTOlPsl6BQtPYcjokzaAashtToYjZYE5HOaas5spbirFkUZc3AnpLDpJJrMBrM1LdujhvvSitifNFSCjKmYDAY48bkuCqoKPwUeSOwt37Mtud2MfHGciZcP5aMMelcsmweJpuR3X+rih//4m5K5hcy4wuTyRjt4oKvzSB7Qibb/9R7fFjtFq795RLGLi0lvcxF3tQcLvp/F9Cyqw1PY/wPSslQ49lEiX0yxfbJ2M1ZTM74FEaDicNdO+LG13oqybaVMto5G7s5kwrXfJyWXA56twC9vddaz2bGOueSlzIWhyWHqVmXEwh3caS7OpGpnVTd4dUU5s+hMH82aWm5jC+/HoPBTH3TxgHi15CZWUFp8ULSUnMZU7YEh72AQ/UfA7151x1eQ9moxeRkTcSels+k8TcTDHhoadmVyNROqta3heLUSRSlTsRuymSSc1Hvda17d9z4g76tZFtHMTptJnZTJhWOeTjNORz0bYvGFKaMp9x+AVmWgUc9xPAY8cV98eLF3HfffQD88pe/pKKiApvNRl5eHjfffHPC2xNRYdyhFrLMfQerpmlkmYvoCDWdZMs+YRVCqUi/4t3W08D7rc/yUftL7PR+RDASv2eYDJFIGI+vgSxH3xCrpmlkOkbT4TuUxJYNr3BPmObdbRTNK4iu0wwaxXMLaNraEnebI1ubKZobO3RdPL+Apm3NAz5P0NsDGljt5qFp+FmKqDDu4BGyrKOi6zRNI8s6io5AY9xtOoINZNlGxazLto2iI9gb3x12E4j4YmLMBisua/6A+0y0SCSEx1NPZvrY6DpNM5CZPha3uy7uNp2euph4gMyMCtye3ni/v51gj5eM42JMJhtORzGdnvj7TLSICuPuaY4pwpqmkWUppqNnoPe7icwTina2pYSOntO7DorhNeLvuR+zYcMGvvnNb/K///u/LFiwgLa2Nj766KMB4wOBAIFAIPq32+0eknYEI34UCqshJWa9xZBCV0/Hae1jr289VkMqWea+e9XZlmLyLGWkGJ34wm72+daz0f0WF7puQNOS/xksGPahUFjMaTHrraY0uvzxi5we+DsCqLAiJdMWsz4l00ZHTWfcbXytflJPiE/NtNHdGv/DWigQZt0vNlN+RRkWu2VoGn6WgpHu3vfbGDsHwGpMpSvUFnebQNiHxXBCvCGVwNHbT8f+22+fx8UkW0+PD0UEiyX2NpLFYsfXHf84Dwa9mE84LyxmO4Ggp/fxHm90HyfuM3g0Jtn6rmux743FmEJXsD3uNoGIL058KsFI/GF8kVjnTHE/ePAgaWlpXHvttTgcDkpLS5k5c+aA8Y888gg//vGPE9jC07PfV0lDoJq5rmsxan0vf4G1PPpvhykThymTj9pfpK2ngSxL/Alr4twXDkVY/v0PQSkWfn9uspsjhNCJ5HcJT9PSpUspLS1lzJgx3HnnnTz33HP4fAN/Qly2bBmdnZ3Rpa5uaIa/LAYbGlq/yXPBSHe/XsuJDvi2cKC7kjnOq3GYsk4am2p0YtZs+MLxe4eJZjGmoqERPGHyXCDUhdUcf7KcHtjSrWhGrd/kue42PylZKXG3Sc2y4Tsh3tfmJyUrtjffW9g/wtPYxTX/vWTE9NqhdyRKQyN4wmSqQNiH1ZAWdxtrnF5bIOLDakw7+njvf/vt87iYZDObU9Ew9Js8Fwx6sQxwnFssdnpOOC+CPV6slt65Qse2i7tPy8iYT9R3XYt9b4Lhga9rVkNqnPj+ozciOc6Z4u5wONi0aRMvvPACBQUF/OhHP2L69Ol0dHTEjbdarTidzphlKBg0I05TNm3HTYZTStHaU0+6aeCvjBzwVbK/exOznVfhMuec8nn8YS89yt9v2CtZDAYjjtQCWj0HouuUUrR5DpCeqt/JMkazkZwJmRxe33ffUUUUhz9pJG9a/K/05E7L4fAnsfcpD69rIG9q3/t+rLB3HnRz7S+XYEsfWZMnDZoRpyWX1kDfh2KlFK2BugG/CpduKaDVH/shutVfR7qlNz7F6MRqSI2JCUUCdAYaT/r1ukQyGEw4HIW0d+yPrlMqQnvHfpzOkrjbuBwltHXETghsa6/C6eiNt9kysJjttB8XEwr5cXsO4XLE32eiGTQjTnMObcETrmvBQ6SbB3q/82gLxs63aQ3WkW4e+DooEuecKe4AJpOJJUuW8Oijj7J161Zqamp47733Et6O0pRpHPLv5rB/L95QOzu7PiKseiiyjQNgm+d99natj8bv91Wyz7eByfZFpBgdBCI+AhEfIdX7NZiQ6mFP18d09DTRHfbQGjzMZvc7pBpcZFtGxskPUJY7n8OtmzjcugWvv5lddW8QjvRQmDUDgG01f2Vf/YpofCQSxu1rxO1rREXC+Hs8uH2N+AJ992xD4WA0BqA72IHb10h3cGSMWABMvWMiu/+6jz2vV9N+oJOPHllHT3eI8df1TpB670erWfdffd8YmHrbBA6tqWfLH3fSXtPJht9soXlnG1Nu7f3eczgU4d3/9yHNu1q57KcXo8IKX0s3vpZuwj3hpOQYT5ljFoe82znctRNvTxs72t8jHOmhKG0SAFtb/8GejtXR+FLHDFr8tRxwb8Lb08a+zo/pDDYxyj4d6J2gVeqYSbV7PUe69+MJtrC17R2sxjRyU8bGbUMylBRdRH3jBhqaNtHlO8Keqr8RjgQpzJsNwM49f6H6wDvHxS+grX0fBw+tosvXzP7aFXi89RQX9v6mg6ZplBQtoKZuJc2tu/B2NbJz78tYrA6ysycmI8W4SlOnc8i3k8Pdu/GG2tjp/oCwClGU0vtNlm0dy9nrWRuNH5U6jZZAHTVdlXhD7VR51tPZ08yo1KnRmGDEj7unBW+49759V6gdd0/LgF+vE0PnnLnn/vrrr7N//34uueQSMjIyePPNN4lEIowfP/7UGw+xAutYgpFuqnwbCER8OE1ZzHZeHe1ld4e9gBaNr/PvRBFhi2d5zH7GpsyiPG0OGhqeUBv1/r30qCBWQyrZ5mLK0+Zg0OJ/hSwZ8jMmEwx1Ud2wkkDIiyMlj1ljPxcdlvf3dKJpfXkHejx8vOep6N+1R9ZSe2QtGfZSLqi4CwC3r54NVc9GY/Yc7r1oFmZOZ0rpDYlI65TKLy/D3x5gw6+34mvtJntcBlf/4lOkHh2W9zZ2oRn68s6fnsOn/u1iPvllJev/uxJXiYMrHltEZnk6AL4jPmo/7O3x/OVzb8Q813W/XkLhnJHRiy1IHUcw3M2+zo8JhH04LdnMybkxOoTeHfZw/HGeYS1ketaV7O1cw97ONaSZ0pmVfS0OS98Ix2jHbMKqh+1tKwhFAmRYC5mTc2PM/JNky8uZSk9PF/trVxAMenHYC5g++a7ohDh/oIPj83Y5RzF5/K3sr11Odc27pKZkMXXS57Cn9fVgRxUvJBwOsmffa4RCflyuUcyYfBdGw8j4dgRAQUoFwYifKs/63uuaOZvZGddiNca/rmVYCpiWvoR9nvXs9XxMmimdmRlX4TD33XJs9tew3d3XAdva+S4AY9PmUO6QOSbDSVNKqWQ34mSO/ULdzTffzA9/+EO2bt2K3++noqKCH/zgB9x6662ntR+3243L5eKyzLsxGUbOvc1EUCUjo1gk2ujf7j91kA7Vfvrk8zn0Klh26ttdemTeV5/sJiSF8sX/0TA9C6kg73meo7Oz85S3mkfOx+UBrFy5Mu6/hRBCCBHfOXXPXQghhBCnJsVdCCGE0Bkp7kIIIYTOSHEXQgghdEaKuxBCCKEzUtyFEEIInZHiLoQQQuiMFHchhBBCZ6S4CyGEEDojxV0IIYTQGSnuQgghhM5IcRdCCCF0Roq7EEIIoTNS3IUQQgidkeIuhBBC6IwUdyGEEEJnpLgLIYQQOiPFXQghhNAZKe5CCCGEzkhxF0IIIXRGirsQQgihM1LchRBCCJ2R4i6EEELojBR3IYQQQmdMyW5AooU73GiaOdnNSChDtz/ZTUiK2s/mJ7sJSbHzJ1nJbkJSOLdak92EpMhThcluQlKYqxuS3YSEM0RM4DnN2OFtihBCCCESTYq7EEIIoTNS3IUQQgidkeIuhBBC6IwUdyGEEEJnpLgLIYQQOiPFXQghhNAZKe5CCCGEzkhxF0IIIXRGirsQQgihM1LchRBCCJ2R4i6EEELojBR3IYQQQmekuAshhBA6I8VdCCGE0Bkp7kIIIYTOSHEXQgghdEaKuxBCCKEzUtyFEEIInZHiLoQQQuiMFHchhBBCZ6S4CyGEEDojxV0IIYTQGSnuQgghhM5IcRdCCCF0xpTsBpyr6iL7qFW7CeLHTjrjDbNwaVlxY4+oQxyI7KQbLxEipOKgVBtPgaEsGrM8/FLcbcu16ZQZJgxHCmfkYM9uanp2EFTd2A2ZTLTMxWXMjht7uKeKHcE1MesMGFiS9vno3yHVw77gJo6E6+hRAVI0O6PMEygxjx/WPAartnMzBzo+IRjuwmHJYWL2ZaTbCgaMb/TuYV/barpDnaSaMxifeQk5aWOij79d/Vjc7cZnXsLojLlD3v4z5Vm+FvdbHxLu9GIZlU/G56/HOqZkwHjf+m10vPIuoZZ2zPlZpN9yJSnT+45fpRSdry7H+8EnKF83lopSMr9wI+b8+MdQsrRWrqJlw/uEujzYcgopuPTTpBaUDhjfubeSptVv0+Nuw5KeTf7Ca3GMmRR9XCnFkTVv0779Y8L+blKLRlN42c1YM3ISkc5pq6v/mIOHVxEMerGn5TNu7LW4HMUDxje1bGd/7XL8/g5SUrIoL7uc7My+c1cpxf6DK6hv3EAo7MflGMWE8utJTRlZ77ceSc/9DDRGDrJXVTJGm8xcw+U4tHQ2Rz4gqPxx401YGG2YxAWGJVxouJJCbTQ71XpaVUM0ZqHh+phlknYBALnawCdWojWGDrAnuIGx5ulcmHItDkMGG/3LCajuAbcxYWZRyi3RZWHqTTGP7wluoCVcz1TrxVyUcgOl5onsDq7nSKhuuNM5bQ3e3exuWUl5xnwWFN+Jw5LLhoa/EAh1xY1v9x9mS9PrFDumsKD4C+SllbOp8a94As3RmEtLvxazTMm5AoA8+7iE5HQ6utZtpf3FN3DdeBkFP/6/mEsKOPLY04Td3rjxgX21tPz6ReyXzKHgX79BysxJNP9/fyR4qDEa43nzQzzvriHzrhvJ+9HXMVgtHPn506hgT6LSOqXOPZtp/OA1ci+8grGffwBbTiE1rzxFyOeJG++rP0DdG38kY8pcxn7+2zjLp3Lwb8/gb+k7v1s+eY/Wyo8ovOwWxn7uPgxmCzWv/IZIaOTk3dS8jX0H3mL0qEu5YObXsaflU7n99wSD8d/vDvdBduz+E4V5s5k78+vkZE1k667n8XY1RWNqD3/EofqPmVB+A3OmfxWj0cLm7X8gHBk5eeuVFPczcFDtoUgbQ6FhDHbNxQRtDkZM1KsDceMztVxytWLSNCepmp1RhnHYcdGhWqIxVi0lZmlW9WSQS6pmT1Rap1TTs4tiUwVF5nLshnQmWS7EqBmp76k66XZWQ0rfoqXEPNYRbqbQNJZMYz4pBjvF5nHYDRl0RloG2Fvi1XRsoMQ5lWLnVOyWbCbnLMWomTns2R43vrZjE9mpoxmdMRe7JYuKzItxWvM46K6MxlhNaTHLka5qMlNGkWpOT0xSp8Hzj4+wL7oA+8I5mIvyyLzrRgwWC94PN8SPf3c1tqkVOK++BHNhLuk3XY6ltBDv8rVAby/O/c5qXNdfSuqsSVhKCsi691bC7R58m3YmMrWTatn4ARlTLiRjylxsWfkULrkZg8lM+/b18eM3fYSjbAI5F3wKW1YeeRddhS23iNbKVUBv3q2bPyR33lKc5VOw5RRSfOXnCHnduKviH0PJcPDwaory51CYNxt7ai4Tyq/HaDRT37Qxbnxd/RoyMyooLV5IWmouY0uX4LAXcKjhY6A377rDaygrWUxO1kQcaflMHnczwaCH5tZdiUztvJSU4r548WK+8Y1vcN9995GRkUFeXh6//e1v6erq4p577sHhcFBeXs5bb72FUory8nIeeyx2GLOyshJN06iqOnlhGWoRFcZDO5laXnSdpmlkankxxXogSinaVBNdeEjX4g/JBZSfFuop0sbEfTwZIiqMJ9JKlrFvKFrTNDKNBXREmgfcLkyID30v84HvL2z2v4c30hHzeLoxh+ZwHf6Ir/e1CTfii7jJMhYOVyqDElFh3IEmslL7hmQ1TSMrZRQd/vq423QE6slKiR3CzU4tGzA+EOqi2befYsfUoWv4WVKhEMGaemyTyqPrNIMB2+SxBKsPxt0mUHUwJh7ANrWCwNH4cHM7kU5PTIwh1YZ1bEk0Jtki4RDdTYewl/aNoGiaAXvpOHwNNXG36W6oIa20ImadvWwC3fW98T2dbYS6PKSN6tun0ZpCSv4ougfYZ6JFIiE83noy08dG12magYz0sXR64o+idXrqYuIBstIr6HT3xvsD7QR7vDExJpMNp6M4GiOGT9J67n/4wx/Izs5m/fr1fOMb3+BrX/sat9xyCwsWLGDTpk1cfvnl3HnnnXR3d/PFL36RZ555Jmb7Z555hksuuYTy8vK4+w8EArjd7phlKPQQRKGwYItZb8FGkPjD8gAhFeT98Mu8F/kzlZEPGa/NIkvLjxvboA5gxEzOCBqSD6pAb94n9LytWgqBAW5HpBlcTLYsYIb1UqZaL0YB67vfwh/pG86eaJlLmsHFh91/Ybnvj2z0L2eiZR6Zxry4+0y0YLi7N29jWsx6qymNQDj+sHwg1IXFmBobb0wdMP6wZwcmg4W8tIq4jydD2OODSASjK3bkyOB0EO6MPzwd7vT2izc67YQ7vUcf790uXkxkgH0mWri7C1QEU6ojZr0p1UGoK34bQ12euPE9R4fxQz53dF1MTJqDngH2mWg9PT4UESzm2PfGYrYPOCwfDHqxWGLPC4vFTqCnN6fA0e0sFnu/mGDPyMhbz5JW3KdPn84Pf/hDKioqWLZsGTabjezsbO69914qKir40Y9+RGtrK1u3buXuu+9mz549rF/fOyzW09PD888/zxe/+MUB9//II4/gcrmiS0nJwJOAEsGImXmGy5lrWMpYbSr7VCVt6kjc2Hp1gHxtFEbNmOBWDq10Yw6F5rE4jZlkGvOZYV2MWbNxKLQ3GnMwtJvOcAszrJdyYcq1jLfMYVdwHa3h+L1cPTrs2U6BfSJGg8xvFUIMjaQV92nTpkX/bTQaycrKYurUvmHJvLzentuRI0coLCzkmmuu4emnnwbg73//O4FAgFtuuWXA/S9btozOzs7oUlc3NMNAZixoaP166UH8/Xrzx9M0jVTNgUPLoNQwgVytmJpI//tO7aoZH54RNSQPYNGsvXmfMHkuoLqxagPnfTyDZsBpyMQX6f3UHlYh9gU3M94yh1xTCQ5DBqPME8g3lVHTMzLuwVqMKb15n9DrDoS6sJ7Qmz/GakojGPbFxod9cePbug/R1dNGsXPkDMkDGB2pYDBEe93HRNwejC5H/G1c9n7xYXdfb/7YdvFiDAPsM9GMKWmgGfpNngv5PJjS4rfRlOaIG28+2lM3pTqj62JiujyYB9hnopnNqWgYCPbEvjfBHm+/nvcxFoudYDD2vAgGvVjNvTlZj253Ys8/GPRiMY+MvPUsacXdbDbH/K1pWsw6TdMAiEQiAHz5y1/mxRdfpLu7m2eeeYbPfvazpKbGDn0ez2q14nQ6Y5ahYNCMOMigTfXNCD12Hz1dO/2vdyggQrjf+nq1HwcZOLSMoWjukDFoRhyGLFrDfTOAj90jTzec3td5lIrgibRHJ9UpIigigBYTp6GBUkPW9rNh0Iw4rXm0+vruCSulaO0+SLot/ryAdGshrd21MetafbVx4w95tuG05uG05g5tw8+SZjJhKSvEv7M6uk5FIvh3VmMZOyruNtbyUTHxAP4dVViPxhtzMjC4HDExkW4/geq6aEyyGYwmUvKK8R7cF12nVATvwX2kFpTF3SaloIyu4+IBvLV7SSnsjTe7MjGlOWJiwgE/3Y0HSRlgn4lmMJhw2Atp69gfXadUhPaO/bgc8Uc9XY4S2jti3++2jipczt54mzUDi9lO23ExoZAft+dQNEYMn3NmtvzVV19NWloav/rVr3j77bdPOiQ/3EZp46lX+6mPHKBLudmtNhAmRIE2GoDtkY+pimyNxh+I7KRVNeJTXrqUm9rIbhpVDQVa7KSrkOqhSdWNuF77MWXmiRwO7eNwTzXeSAe7gh8TViEKzb3zHrYFVrEvuCkaXx3cQkuoHl/EgzvcyrbAKvyqiyJz771lk2Yhw5DH3uDGoxPpPBzuqaI+tJ9c08i42AOUpc/hkGcrh93b8QZb2dHyLmHVQ5FjCgBbm95kT+uH0fjS9Fm0+Go40PEJ3mAr+9pW0xloZJRzRsx+Q5EATd49I2oi3fEcVyzE+8EneFdtpKf+CO3PvkYkEMS+cDYALU/9iY4/v90Xv/Qi/Nv34n7rI3rqj9Dx6nKCBw5jXzIf6P3A7rz8Ijr//h6+zTsJ1jXS+tSfMWY4SJ01KW4bkiF79iLat31M+45P8Lc2Ub/8L0R6gmRM7v39gUNvPU/jR6/3xc9aiKdmNy0bVhJoa6Jpzdv4m+rImnExcHQC5sxLOLLuXdzV2/E313Po7ecx2Z04y6ckJcd4RhVdRH3jBhqaNtHlO8Lu6r8RDgcpyOt9v3fs+QtVNe9E40sKF9DasY/aQ6vo8jWzv3YFbm89xQUXAr15lxQtoKZuJc2tu/B2NbJj78tYLA5ysiYmI8Xzyjlzk89oNHL33XezbNkyKioqmD9/ftLakm8YRU8kwH61nYDy4yCdmYZF0eFpv/JFRx4AwoTZHdlIgG4MGEnDwWTtQvINsQWsUfX2DvO1kVPYjpdvGk1QBajuqSQQ7MZhyGSW7bJoT9wf6UIz9OXdo4LsDK4loLoxaxachizm2q7EbkiPxkyzXsK+nk1sC3xEjwpi09Iot8yk2DRyvu9dYJ9AMOxjX/tqAiEfTmsOcwpuxmrqHWbvDrnhuPc7w1bE9Lxr2Nu2ir2tq0gzpzMr/0Yc1tgRjgbvbhRQYB+ZF7q0edOIeLx0vrqccKcHy6gCcr99T9/wemtHzHFurSgl+//cRscr79Dx8j8w52WT883PYynumzjquPoSIoEgbc+8SsTnxzqulNxv34NmMfd7/mRxjZ9JyOflyJq3Cfnc2HKKKPvMV6LD8kFPe8z7nVo4mpKrP0/T6rdoWv0GlvQcRl1/D7bsvm+WZF/wKSI9Qerf/TPhQO+P2JR95isYTCMn77ycqQR7uth/cAWBoBdHWgEzptwVHV73B2Lf73TnKCaPv5X9tcuprn2X1JQspk38HPa0vsmwpUULCYeD7K56jVDIj8s5iplT7sJoGDl565WmVOLHPxcvXsyMGTN44oknouvKysq47777uO+++/oap2m8+uqr3HjjjQDs37+fsWPH8uijj/Ld7353UM/pdrtxuVwsNnwGk3Z+HVgGmzXZTUgKQ/7IGupOlJ3/Ev+XEvXOufX8PM7z1vtOHaRD5uqGUwfpTCgSZHnTb+ns7Dzlreak9NxXrlzZb11NTU2/dSd+7jh8+DBms5kvfOELw9QyIYQQ4tx3TgzLBwIBmpubeeihh7jllluiM+mFEEII0d85MaHuhRdeoLS0lI6ODh599NFkN0cIIYQY0c6J4n733XcTDofZuHEjRUVFyW6OEEIIMaKdE8VdCCGEEKdPirsQQgihM1LchRBCCJ2R4i6EEELojBR3IYQQQmekuAshhBA6I8VdCCGE0Bkp7kIIIYTOSHEXQgghdEaKuxBCCKEzUtyFEEIInZHiLoQQQuiMFHchhBBCZ6S4CyGEEDojxV0IIYTQGSnuQgghhM5IcRdCCCF0Roq7EEIIoTNS3IUQQgidkeIuhBBC6IwUdyGEEEJnTMluQMJFwqCdX59pIj5fspuQFJH9NcluQlJM/P75+X5XPZmf7CYkxb7JlmQ3ISkmPZyS7CYkXuT0a9f5VeWEEEKI84AUdyGEEEJnpLgLIYQQOiPFXQghhNAZKe5CCCGEzkhxF0IIIXRGirsQQgihM1LchRBCCJ2R4i6EEELojBR3IYQQQmekuAshhBA6I8VdCCGE0Bkp7kIIIYTOSHEXQgghdEaKuxBCCKEzUtyFEEIInZHiLoQQQuiMFHchhBBCZ6S4CyGEEDojxV0IIYTQGSnuQgghhM5IcRdCCCF0Roq7EEIIoTNS3IUQQgidkeIuhBBC6IwpGU+6ePFiZsyYwRNPPEFZWRn33Xcf9913HwCNjY3ceeedrFmzBrPZTEdHRzKaeEp1qopa9hLEjx0X45mJS8scML5JHaKaHfjpIgU7FUwlWyuIPh5SIarYRjP19BAghTRKKKdYG5uIdE7bUOcN0KXc7GMb7TSjUNhxMo352LTU4U7ntA0272MaVR3bWUcOhUzXFkTXV6sdNHEIPz4MGHCSwVgm49KyhjONQTvYtY0DXZUEIz4c5iwmOBaSbskbML7RX0WVZz3dYQ+pJhfjHPPJsZZGH9/WsYJ6/56YbbIsJczJvG7YcjgTnf9YR8ffVxPu8GIpzSP7nmuwlRcPGO9du522P71HqLkDc34mmXdcTtrMcdHHlVK0//k93Cs2EunyYxs/iuwvX4elYGS935731uJ++wPCnV4sJQVkfO56rGNKBoz3fbKVjr++S6ilHXNeFuk3X0XKtAnRx5VSdL72Lt4PP0H5urGUl5F5542Y87ITkc55Lek9908++YSvfOUr0b8ff/xxGhoaqKysZO/evUls2cAaVR172coYJjGXJThIZzMfEVT+uPEdqoXtrKOQMuaxhFwK2cIavKozGrOPLbTSyGQuYD5XUEIFe6ikWdUnKq1TGo68fcrLBlaShoPZLOJCljKaiRiSf2hGDTbvY7pVF/vYSjr9L2RpOBjPDC5kKXNYjI1UNvERQRUYrjQGraF7H7s9qym3z2F+9i04TNlsbH+dQNgXN7492MDWjncpSp3I/OxbyLWOZnP7W3h6WmPisi2jWJxzd3SZnr40EemcNu+abbQ8+zYZNy2m+GdfxVKaT8PDzxLq9MaN9+85SNP/9xccl86i+GdfI+2CiTT+xwsEDjZFYzr+torOt9aR8+XrKPq3r6DZLDQ8/CyRYE+i0jqlrvVbaH/pdVzXL6HgwW9gLingyOO/I+yOn3egqpaWp17EvnAOBQ9+k5SZk2n+r/8leKgxGuN56wM8y9eQeeeN5P3gnzBYzRz5z6dRPSMnb71K+hU0JyeH1NS+Hlp1dTWzZ8+moqKC3NzcJLZsYAfZSxGjKdTKsGtOJjALI0bqqYkbX0cVWeRRpo0nTXMyVpuCgwzqqI7GdNBKAaVkarmkaGkUa2Ow46KTtgRldWrDkXc128kinwptGk4tg1TNTo5WiEWzJSirUxts3tDbY9nOesYwiRTS+j2er40iS8sjVbNj11yMYzphQnjpGL5EBqnWt4Xi1EkUpU7EbspkknMRRs3E4e7dceMP+raSbR3F6LSZ2E2ZVDjm4TTncNC3LSbOoBmxGlOji9kwct5rgI431uC8bDbOS2dhKc4l58vXoVnMeN7fFD/+rY9JnVFOxvUXYynOIfOzl2EdXYD7H+uAo73XN9eS8ZlLSLtgItbSfHL/6TOE2z10fRL/tUwGzzursF8yF/vFczAX5pF5540YLBa8qzbEj1++GtuUcTivXIS5MJf0T1+OpbQQ73trgd683ctX47r2U6TOnIylpICsL32WcIcb36adiUztvJT04l5WVsYTTzwR/ffLL7/Ms88+i6Zp3H333QB0dHTw5S9/mZycHJxOJ5/61KfYsmVLUtobURE8dJBJ3wcPTdPIJI8OWuNu00ErmcQOZWaRR+dx8elk0UIDftWNUoo2dQQfXrIYeAg0kYYjb6UULTSSip1N6iM+UH9nvVrBEXV4+BIZpDPJG2A/O7FgpUgbfVrPcZj9mDBjJ30omn3WIiqMu6eZLEvfULSmaWRZiunoaYy7TUewiUxL7NB1tqWEjp6mmHVtwcO8f+QZPmp+np2dHxCMnHwEJJFUKERgfwOpU/tuh2kGAylTx+LfdyjuNoG9daRMGROzLnV6Of69dQCEjrQT7vCSctw+jak2rOVFBPbVDUMWg6dCIYK1h7FNLI+u0wwGbJPKCVbXxt0mUF2LbVJ5zDrb5HEEjsaHW9qIdHpiYgypNqxjSqIxYvgk5Z77QD755BO+8IUv4HQ6efLJJ0lJSQHglltuISUlhbfeeguXy8VvfvMbLrvsMvbu3UtmZvz7noFAgECgb4jT7XYPSRt7CKBQWIjtbViw0kX85wjix4L1hHgbQfouauOZwS42sYo30NAAjYnMJkPLGZJ2n63hyDtIgDAhatjDWCZTwVRaaWQra5mtFo2I3M8k7w7VQj01zGPJSffdrOrZzjrChLFiYyYLsWjWk26TKMGIH4XCaoid92AxptAVbI+7TSDiixOfSjDSN4yfbR1Fnm0MKUYnvnAn+zzr2Nj+OhdmfgZNS3pfg7DbB5EIRlfsaIvJlUZ3fXPcbUIdXozp9ph1Rped8NFh/HCHN7ruxJhQR/wh70QLe47m7Yxto8Fpp6chft7hTm+/eKPTHh3GP5Z/vJjIAEP9YuiMqOKek5OD1WolJSWF/Px8AFatWsX69es5cuQIVmvvhe+xxx7jr3/9K3/5y19i7tcf75FHHuHHP/5xwtp+tuqoopNWprMAG6l00MIeNmNVNrK0kdF7H3oKgBwKKdV6Jx85SKdDtXKI/WSQ/OI+WCHVw3bWM5FZpyzUmeQyj6X0EOAwB9jGx8xVnxpRtySGWkFKRfTfDnMWDlMWH7U8R1uwnizrwBPWhBCDk/yPyqewZcsWvF4vWVlZ2O326HLgwAGqq6sH3G7ZsmV0dnZGl7q6oRn+MmNFQ4vpdUNvL/TE3t0xvb3VwAnx/mh8WIWpYjvjmE6OVohDS6dEKyePYg4yMiYVDkfex/aZhjMmJg0HfuJP2kq0webdTRd+fGxhDSvUy6xQL9NALc3Us0K9jE/19ViMmolUzY5Ly2KSNgcNA4dPch8/kSwGGxoagUjs+xAMd2MxxP8Wg9WQGifeN2A8QKrJhVmz4Qt3DhiTSEZnKhgMhDu7YtaHOrswpjvibmNKt0d758eEO73RnvqxXn24s3+M6YQef7IYHUfzPqFHHXF7+404RLdx2fvFh919vflj28WLMThHRt56NuKLu9frpaCggMrKyphlz549fPe73x1wO6vVitPpjFmGgkEz4CCdNo5E1ymlaOMI6cT/Wks6WTHxAG004Toar4igjvZij6ehxV2fDMORt0Hr/QqYD09MjA8vNkbG1+AGm3cqDi5kKfNYEl1yKCSDHOax5BR5KSKEhyGLwTNoRpzmHNqCffMflFK0Bg+Rbs6Pu026JY+2YOx96dZgHenmgUee/GEvPcrfbzg/WTSTCeuYAnzb9kfXqUiE7u37sVXEH1mwjiuhe/v+mHW+bdXYxvV+hcyUm4Ex3U73cfuM+PwEqg5jrRj4a2aJpJlMWEqL8O+qiq5TkQj+XVVYxpbG3cY6tjQmHsC/cx/Wo/HG7EwMLkdMTKTbT2B/XTRGDJ8RX9xnzZpFY2MjJpOJ8vLymCU7OznflRzFOOo5QL2qoUu52c0mwoQooAyA7Wo9VapvhnAJ5bTSSK3aS5dyU6124KadEnon2Jg0M+lks49ttKkjdKsu6lUNDdSSS1EyUoxrqPMGKGU8TdRxWO3Hp7zUqSpaaIiJSbbB5G3UjNg1V8xiwtw7WU5zYdAMhFWIKrWNTtVKt+rCrdrZoTYQoJs8Rs7QdGnqdA75dnK4ezfeUBs73R8QViGKUnq/x7ytYzl7PWuj8aNSp9ESqKOmqxJvqJ0qz3o6e5oZlToVgFCkhz3uNXQEG+kOuWkNHGJz+1ukGl1kW0clJcd40q9ZgOe9jbg/2EzwUDMt//M6KhDEsXgWAE3/9TKtz7/bF3/Vhfi2VNHx99UEDzfT9uf3CFTX47xiHtA7EdF19XzaX/2Arg27CRxsoum/X8GY4SDtgglx25AMjssvxvvhJ3hXb6Sn/gjtf/wrkUAQ+0WzAWj5n5foePntvvglF+Hfvhf3Pz6kp+EIHa+9S7DmMPZPzQd683YuuYjO19/DV7mT4KFGWv/nTxjTnaTOmpSUHM8nI+qeezxLlixh/vz53HjjjTz66KOMGzeO+vp63njjDT796U8zZ86chLcpXyuhRwXYz04C+HHgYiYXYz16r9SP7+ikuF7pWjZT1Dyq2U4V20nFznQWYNdc0ZipXEgV29jBenoIYiONsUyhiDH9nj9ZhiPvXK2ICWoWNexhD5Wk4mAq80nXRs6PXAw271PT6MJDA2sJEsSMBScZzGZxzGuTbAUpFQQjfqo86wlEfDjN2czOuBarsbeX3R32wnF5Z1gKmJa+hH2e9ez1fEyaKZ2ZGVfhMPeOcGiahifUSn3HHnoiAayGNLKtJZTb52LQjMlIMS77gqmE3T7a//QeoQ4v1rJ8CpbdGR1CD7V2ohn68raNH0XeN26m7aUVtL64HHN+FvnfvR3rqL4Ri/TrL0YFgjQ/9Tcivt4fsSlYdicGiznh+Q0kbe50Ip4uOv/6LmG3B0tJIbn3fxGjq/d2RLitA03ry9taXkr2vbfR8eo7dLzyD8y52eT83zuxFPeN7DiuWkQkGKTtD68Q8fmxVpSRe/89aOaRk7deaUqphI/7nuwX6m688UbS09P5/e9/H433eDz84Ac/4OWXX6a5uZn8/HwuueQSHnnkEUpKTm9Yy+1243K5WMwNmDQ5sIR+GfNG5u9DDLeqJ+PfLtC7Hq8l2U1IikkPtyS7CQkXigRYfuAXdHZ2nvJWc1KKezJIcRfnCynu5xcp7uePwRT3EX/PXQghhBCDI8VdCCGE0Bkp7kIIIYTOSHEXQgghdEaKuxBCCKEzUtyFEEIInZHiLoQQQuiMFHchhBBCZ6S4CyGEEDojxV0IIYTQGSnuQgghhM5IcRdCCCF0Roq7EEIIoTNS3IUQQgidkeIuhBBC6IwUdyGEEEJnpLgLIYQQOiPFXQghhNAZKe5CCCGEzkhxF0IIIXRGirsQQgihM1LchRBCCJ2R4i6EEELojBR3IYQQQmdMyW6AEGJohY80J7sJSTH2i95kNyEp3qpak+wmJMX8976a7CYkXLjHDwdOL1Z67kIIIYTOSHEXQgghdEaKuxBCCKEzUtyFEEIInZHiLoQQQuiMFHchhBBCZ6S4CyGEEDojxV0IIYTQGSnuQgghhM5IcRdCCCF0Roq7EEIIoTNS3IUQQgidkeIuhBBC6IwUdyGEEEJnpLgLIYQQOiPFXQghhNAZKe5CCCGEzkhxF0IIIXRGirsQQgihM1LchRBCCJ2R4i6EEELojBR3IYQQQmekuAshhBA6I8VdCCGE0Bkp7kIIIYTOmJLdgHNVnaqilr0E8WPHxXhm4tIyB4xvUoeoZgd+ukjBTgVTydYKoo8vV3+Ju105UynTxg95+8/UYPL2qk6q2YmHdvz4GMd0RmkVA+67Ru2miu2UUM54bcYwZXBmBpP3YbWfBmrx4gbASQZjmRITH1IhqthGM/X0ECCFNEoop1gbm5B8TledqqJW7TmadzrjtZMf58c0qoNsV+vIoZDphotiHutSbvaprbTTjEJhx8k0bQE2LXW40hi0gz27qenZQVB1YzdkMtEyF5cxe8D4xlANVcFK/MpLquakwjKLHFMxABEVoapnMy2hw/iUF7NmJtNYQIV5FjbDyMkZ4JfPdPDYLztobA4zfZKFJ/8th7kzbQPG//nvXh7891ZqDoWoGG3mkR9mcfVladHHX3nDy2+e7WTTtgBt7RE2vlvCjCnWRKRy3pOe+xloVHXsZStjmMRcluAgnc18RFD548Z3qBa2s45CypjHEnIpZAtr8KrOaMxCro1ZJjEHgFyKEpLT6Rhs3mHCpJJGOVOxMPAFAqBTtXGI/dhxDUfTz8pg826nmTxGMZtFXMClWElhMx/hV93RmH1soZVGJnMB87mCEirYQyXNqj5RaZ1So6pjr9rCGG0Sc7WlOHCxWX04YN7HdKsu9qmtpNO/GPqUlw3qfdJwMltbzIXa5YzWJmEYQZeixtAB9gQ3MNY8nQtTrsVhyGCjfzmB496/43WEj7At8BFFpnIuTLmWXFMJlYGVeCLtAIQJ4Q63McYyjfkp1zDdupiuiJvKwPuJTOuUXnrNw7cfauFfvp3Jhn+UMG2Slatur+dISyhu/JpPurnja4188XNONr5Twg1XpvGZexrYvjsQjenyRbh4XgqP/CArUWmIo0bOGXUOOcheihhNoVaGXXMygVkYMVJPTdz4OqrIIo8ybTxpmpOx2hQcZFBHdTTGqtlilmbqySCHVM2eoKxObbB5u7RMKrRp5GslJ714h1SIHaxnIrMxYR6m1p+5weY9RZtHiTYWh5ZOmuZkEnNQKNo4Eo3poJUCSsnUcknR0ijWxmDHRSdtCcrq1A6qY3mP7s1bm33SvAGUUmxX6xijTSaFtH6PV6vtZJFPhWEaTi2DVM1OjlaIRTv5h79EqunZRbGpgiJzOXZDOpMsF2LUjNT3VMWNr+3ZRZaxkNGWKdgN6ZRbZuI0ZFLXswcAs2ZhTspS8k1lpBlcpBtzmGiZizvSSnfEm8jUTuqJ33Tw5Ttc3HObk0njLfzq0RxSUzSeecETN/7/+59Orrg0le98PYOJ4yz86/eymDXVyn8/3ddpufMWJ//yQCZLLhlZIxTnAynugxRRETx0kEludJ2maWSSRwetcbfpoJVM8mLWZZFH5wDxAeWnhQaKGD10DT9LZ5L36drDZrLIJ0vLO3Vwgg1F3mFCKCKYj/vgkk4WLTTgV90opWhTR/DhJYuR8Rr05t1O5nHvSTRvNXDe+9VOLFgp0vofu0opWmggVXOwKfIhH0T+xvrICo6ow8OSw5mIqDCeSCtZxr5bZpqmkWksoCPSHHebzkhzTDxAlrFwwHiAEEGgt/CPBMGgYuPWAJctTImuMxg0LluYytqN8UdqPt7gZ8nC2KJ9+eJUPh4gXiSWbu+5BwIBAoG+4SG32z0k++0hgEL1G2a2YKWL+M8RxI8F6wnxNoLEPwkaqMWIiZwRNCR/JnmfjkZVh5t25nLZ2TZxWAxF3lVsw0pKzAe88cxgF5tYxRtoaIDGRGaToeUMZfPP2MB52+gifk+uQ7VQzwHmaUvjPh4kQJgQNWo3Y7UpVDCNVhrZqtYwm8UjIvegOpq3lhKz3qql0BWJ/34HlL9fvEWzEYzEH8YPqzB7g5vIN47GNEKKe0tbmHAY8nKMMevzcozsqQrG3aaxOURuv3gTjUfCw9ZOcfp023N/5JFHcLlc0aWkpCTZTTpt9dSQzyiMmvHUwecwv/Kxl0qmMFe3udao3TRSxzTmx+RYRxWdtDKdBczlMsYxjT1splU1JbG1Zy6ketiu1jFRm41FG2jClAIgh0JKtXE4tHTKtAlkU8AhVT3ANvoSURG2Bj4AYJJ1XpJbI/RMtz33ZcuW8cADD0T/drvdQ1LgzVjR0Pr1uoMEBpw01ttLD5wQ748b366a8eFhKiPrxD+TvE/FTTtBAqxnxbHrPgpFBy0cUtV8is+gadrZNv2snE3etWoPNexhFgtxaOnR9WEVportTGdB9BsTDtLxqA4OsndEDM0PnHf847abLvz42KJWx7yXACsif2G+diU2UtHQSNOcMdum4aSDluFJZJAs2tG8T5g8F1DdWAeYF2DVbP3ig8qPxRDbmz9W2LtVF3NsS0dMrx0gO9OI0QhNzbG97qbmMHm58ctEfo6JI/3iQ+Tn6vOD+rlGtz13q9WK0+mMWYaCQTPgID1mcpRSvZOl0ok/IzSdrJh4gDaacMWJr6cGBxkxxWAkOJO8TyWTXC5kKfNYEl2cZJDPKOaxJOmFHc487xq1h/3sYiYX4zzhq2OKSLTwHU9Di7s+GXrzzqBNxclb6593Kg4u1C5nnrY0uuRQSAa5zNOWYiMVg2bASSY+FTus78ODjZEx4cqgGXEYsmgNN0TXKaVoCzeSboh/28BlyKE13BizrjXcEBN/rLB3RTzMsS0dURMIASwWjdnTrLy3qu9DSiSieG+Vj/mz47f1wjk2Vqzyxaxb/mE3Fw4QLxJLt8V9OI1iHPUcoF7V0KXc7GYTYUIUUAbAdrWeKrUtGl9COa00Uqv20qXcVKsduGmnhNjvNIdUD00coujofkaaweYdURE8qgOP6iBChADdeFQHPtU7Q9ikmbFrrpjFgBEzFuzayPlK3GDzrlG7qWYHk5iDjTQCyk9A+Qmp3q8UmTQz6WSzj220qSN0qy7qVQ0N1I6orz6O0sZRz/6+vNUJeUfWUxXpzduoGfu9lybMmDD1vq9a76WmVBtPE3UcVvvxKS91qooWGijRypOVZj9l5okcDu3jcE813kgHu4IfE1YhCs29bdwWWMW+4KZofKl5Iq3hw9T07KAr0klVsBJ3pJUSc+/vU0RUhC2BlXRGWplmvRilFIFIN4FINxE1cu5P3/d/0vmf59z84U9udu0N8vXvNdPlU9x9mwOAu77RxD//W98Iyze/7OIf7/v4z1+3s3tfkB8/1sqGLX7+6Yt9525be5jK7QF27u29b7+nOkjl9gCNR+J/vU4MnXN6WP6//uu/ePXVV1mxYkVCnzdfK6FHBdjPTgL4ceBiJhdHh+38+I5OkuqVrmUzRc2jmu1UsZ1U7ExnQb8C1khd7/4ZlbhkBmGweQfoZh3Lo3/Xspda9pJONnNYnOjmn7HB5n2I/SgibOPjmP2MZiJjmQzAVC6kim3sYD09BLGRxlimUMSYxCV2CvlaCT0E2K92HM07nZnawhPyHpxcrYgJzKZG7WYPm0nFwVRtPunawD8Qk2j5ptEEVYDqnkoCwW4chkxm2S7DenTSnD/ShWY47vw25jLVupCqYCX7gptJ1ZzMsC7GYcgAIKB8NIcPAbDW/3rMc82xXU6mMT9BmZ3cZ29w0NIa5qFH22hsDjFjspU3ny8kL6e3TNQd7sFwXHdwwQUp/PGX+fzo31v5wSOtVIy28MozBUyZ0Dfn4m/vdPGl+/pGfz731d45JT/6dgYPfke++z6cNKXUyBgHPAMPPfQQv//976mpqTllrNvtxuVysZgbMGkj77vUQgyZEXA7IxkMKSmnDtKht6rWJLsJSTH/O19NdhMSLtzjZ+OffkhnZ+cpbzWf08PyDz300GkVdiGEEOJ8ck4XdyGEEEL0J8VdCCGE0Bkp7kIIIYTOSHEXQgghdEaKuxBCCKEzUtyFEEIInZHiLoQQQuiMFHchhBBCZ6S4CyGEEDojxV0IIYTQGSnuQgghhM5IcRdCCCF0Roq7EEIIoTNS3IUQQgidkeIuhBBC6IwUdyGEEEJnpLgLIYQQOiPFXQghhNAZKe5CCCGEzkhxF0IIIXRGirsQQgihM1LchRBCCJ2R4i6EEELojBR3IYQQQmdMyW6ASABNS3YLkkOpZLcgOc7TvCPd3cluQlJM//evJ7sJSfHKI48muwkJ5/VEmPWn04uVnrsQQgihM1LchRBCCJ2R4i6EEELojBR3IYQQQmekuAshhBA6I8VdCCGE0Bkp7kIIIYTOSHEXQgghdEaKuxBCCKEzUtyFEEIInZHiLoQQQuiMFHchhBBCZ6S4CyGEEDojxV0IIYTQGSnuQgghhM5IcRdCCCF0Roq7EEIIoTNS3IUQQgidkeIuhBBC6IwUdyGEEEJnpLgLIYQQOiPFXQghhNAZKe5CCCGEzkhxF0IIIXRGirsQQgihM6bBBC9evJgPPvgAgM2bNzNjxozhaNOIbwNAnaqilr0E8WPHxXhm4tIyB4xvUoeoZgd+ukjBTgVTydYKoo/vUJ/QQG3MNlnkMVNbOGw5nIk6VUWt2nM073TGa6fKu45qdVze2rTYvCPr4+dtuGTYcjgTg3m/vaqTanbioR0/PsYxnVFaRUzMIVXNIfbTTRcAdpyMZmLMazMSDPY4P6ZR1bGddeRQyHRtAQARFaGa7bTQSDddmDCTSS4VTMWqpQx3KoMymON8Q2QlHTT3W59FPjMNvefvuXKct25ZRcuG9wn5PNiyCym49NOk5pfGjW3btpaOXRvwtzYCkJJbTN5FV8fEh4MBmla/jrt6O+HuLiyuLLJmLCRz2oKE5HM+G3TP/d5776WhoYEpU6ZQU1ODpmlxl48//ji6TXd3Nw8++CDjxo3DarWSnZ3NLbfcwo4dO2L27fP5WLZsGWPHjsVms5GTk8OiRYt47bXXojGvvPIK69evP4uUz16jqmMvWxnDJOayBAfpbOYjgsofN75DtbCddRRSxjyWkEshW1iDV3XGxGWRx0KujS5TmJeIdE5bo6pjr9rCGG0Sc7WlOHCxWX148rzVOgq10czTlpJLEVvU6jh557NQuy66TNEuTEQ6p22w73eYMKmkUc5ULNjixlhJoZwpzOMy5nIZGeTGPSaSabB5H9OtutjHVtLJjlkfIYyHDsYwkXksYTrz8eGhkjXDmcagDfY4n64tiDl+L9QuR0MjTyuJiRvpx3nnns00fvgauRdewdjPPYAtp5CaV58i5PPEje86VI1r/CxG3/R1xn72m5gd6dS88ht6vB3RmMYPX8Nbs5viK+6g4gvfJ2vmJdS//wru6u0Jyur8NejinpqaSn5+PiZTX6d/+fLlNDQ0xCyzZ88GIBAIsGTJEp5++ml++tOfsnfvXt58801CoRDz5s2L+RDw1a9+lVdeeYVf/OIX7N69m7fffpubb76Z1tbWaExmZiY5OTlnk/NZO8heihhNoVaGXXMygVkYMVJPTdz4OqrIIo8ybTxpmpOx2hQcZFBHdUycASNWzRZdzJolAdmcvoPqWN6je/PWZp88b7WPLPL78jYczVtVxcQZMIzsvAf5fru0TCq0aeRrJRgGOMVytEKytQJSNQdpmoNybQpGTHTSNoyZDM5g8wZQSrGd9YxhEimkxTxm0szM0i4hTyshTXPg0rIYz8zeEQ7lG+ZsTt9gj3OzZok5fttowoCRPIpj4kb6cd6y6QMyplxIxuS52LLyKbzsZgwmM+074nemSq76PFnTLyIltwhrZh5FSz4LKLwH90VjfA01pE+6AHtJORZXJplT52PLKaS76WCCsjp/DWpYfiBZWVnk5+fHfeyJJ55g7dq1bN68menTpwNQWlrKyy+/zLx58/jSl77E9u3b0TSNv/3tbzz55JNcffXVAJSVlUU/JIwUERXBQwdlTIiu0zSNTJVHB61xt+mglVLGxazLIo9m6mPWtdPMB+rvmDGTQS5jmYxFsw59EmegN+92yrQ4eatW0Ppv00ErpdqJeefTzOGYde0080Hkb315a1NGWN6De78HSylFE4cIE8ZF1pDs82ydad772YkFK0XaaDpUyymfJ0QPACbMZ9/oIXAmx/mJDqsD5FOCUYu9vI7o4zwcovvIIXIuuCy6TtMM2EeNw9dQc3r7CAVR4TBGW2p0XWpBGZ79O8iYPBdTmouuQ1UE25uxX3LDUKcgTjAkxf1knn/+eZYuXRot7McYDAbuv/9+7rjjDrZs2cKMGTPIz8/nzTff5DOf+QwOh+OsnjcQCBAIBKJ/u93us9rfMT0EUKh+w60WrHQR/zmC+LFgPSHeRpC+Yb4s8smliBTS8OGlmu1UsooL1KfQtNO4ogyzgfO20UX8YbvevE+I16wxw5tZWj65FPflrbZRqT7iAi4b4XkP/H6fLq/q5BPeI0IEIyamMx+75jyrfQ6VM8m7Q7VQTw3zWHJazxFWYarYRj4lmLSRUdzP5Dg/Xqdqows3k7QLYtaP9OM83N0FKoIpNfa6a0p1EGg7clr7aFr1Oia7C/uovg/0BYs/Q/2KP7Hnf/4VDAY0TaPwsltJKx47pO0X/Q3JbPkFCxZgt9tjlmP27t3LxIkT4253bP3evXsBeOqpp1izZg1ZWVlccMEF3H///axevfqM2vTII4/gcrmiS0lJyak3SqJ8rYQcrRC75iJXK2I6F+GmnXZO78Q6V+Vro2Lz1i4+L/IGSMXBPJZyAZ+imDHs4BO8amg+hCZaSPWwnfVMZNZp9UYjKsI2em/JTWDWcDcvYerVAey4+k2+0/tx3vzJCjr3bKb02nswmPo+qLVt+QhfYy2jrv8S5bc/QP7C62l4/xW8B/cmsbXnhyEp7i+99BKVlZUxy/GUUqe1n0suuYT9+/ezYsUKbr75Znbs2MHChQv5yU9+Mug2LVu2jM7OzuhSV1c36H3EY8aKhhbT6wYIEhhw8lRvLz1wQnz/Xu3xUjU7Ziz4js6mTraB8x44jxNHJwCCauDXCY7P23v2jR4CZ/J+ny6DZiBVs+PUMijXpuIgnTr2nXrDBBhs3t104cfHFtawQr3MCvUyDdTSTD0r1Mv4VN/7eayw+/Exk4UjptcOZ3acHxNWIRo5SKE2+pTPM9KOc2NKGmiGfpPnQj4PprSTj6K2bHyf5k9WUPaZr2LLKYyuj4SCNK1+k4JLbsA5ZjK2nEKyZizENW4GLRvfH5Y8RJ8hKe4lJSWUl5fHLMeMGzeOXbt2xd3u2Ppx4/qGccxmMwsXLuR73/se77zzDv/6r//KT37yE4LB4KDaZLVacTqdMctQMGgGHKTTdtwnbqUUbRwhfYD7pelkxcQDtNF00vurfuWjhyDWsywgQ6U37wzaVJy8tZPkrc4075Hx1agzeb/PlEIRITKk+zxTg807FQcXspR5LIkuORSSQQ7zWIKN3vuwxwq7Dy+zuGTE3HM+5kyO82OaOIQiQj6jTvk8I+44N5pIyS3GW9f34VKpCN66faQWlA24XfOG9ziy7l3KPv0VUvJiR0dVOIKKhOk3UUHTTrvDJ87csP+IzW233cby5cvZsmVLzPpIJMLjjz/OpEmT+t2PP96kSZMIhUL4/Sf/+k0ijWIc9RygXtXQpdzsZhNhQhRQBsB2tZ4qtS0aX0I5rTRSq/bSpdxUqx24aaeE3vtOIRVin9pKp2qlW3XRpprYwhpSsZNFXjJSjGuUNo569vflrU7IO7KeqshxeWsVR/Pe05t3ZAdu2ijRej/8hVSIfZEtsXmr1SMv70G+3xEVwaM68KgOIkQI0I1HdcT0XqvUNtpVM92qC6/q7P2b5tMqDIkymLyNmhG75opZTJgxYcauuTBoBiIqwlbW4qadKcxFoQgoPwHlJ6JGxocaGPxxfky9OkAORf0+sJwrx3n2rEW0b/+Y9p2f4G9ron7FX4j0BMmYNBeAQ/94nsZVr0fjmz9ZwZG1b1G09LOYnZn0dLnp6XITDvaOUhqtNlKLxtK46u9466oIdrbSvmM9Hbs24Bw7NSk5nk+GZEJda2srjY2NMevS09Ox2Wzcf//9vPbaa1x33XX8/Oc/Z968eTQ1NfHwww+za9culi9fHp1QsnjxYm6//XbmzJlDVlYWO3fu5J//+Z+59NJLh6znPRTytRJ6VID97CSAHwcuZnIxVq23l+3Hh3bcp9V0LZspah7VbKeK7aRiZzoLsGsuADQ0PHRSTy2ho5/ms8hjDJMxaMak5BhPvlZCDwH2qx1H805nprbwhLz7pGvZTGEe1eq4vLWL+uetTshbmzLy8h7E+x2gm3Usj/5dy15q2Us62cxhMdA7vL2DTwjgx4T56D4XkqWNnIv9YPM+lQDdtNAAEPP6AMziEjLJHbrGn4XBHucAXcpDBy3M1Pr/KM25cpy7xs8k1O3lyNq3Cfnc2LKLKLvxK9Fh+aC7neN74W1b16DCYere+EPMfnLmXU7e/CsBKLn6TppWv8Ght/9I2O/D7Mwk76Kr5UdsEkBTgxgfWbx4MTNmzOCJJ54AoKamhtGj499feuGFF7jtttuA3h+nefjhh3nppZeora3F4XBw6aWX8tBDDzFlypToNo888gh///vf2bNnDz6fj8LCQq699lp+9KMfkZXVNyR27HkH8wt1brcbl8vFYm4YUff4EmIEzMZNChn6O7+cp8d54zfnJ7sJSfHKA48muwkJ5/VEmDX5CJ2dnafs8J5Vz72srOy07p2kpqby05/+lJ/+9KcnjVu2bBnLli07myYJIYQQ571B33P/5S9/id1uZ9u2/vecEuGqq65i8uTJSXluIYQQ4lwwqJ77c889R3d3NwCjRiVn4s///M//JL0NQgghxEg2qOJeVFQ0XO04p9oghBBCjGTy/3MXQgghdEaKuxBCCKEzUtyFEEIInZHiLoQQQuiMFHchhBBCZ6S4CyGEEDojxV0IIYTQGSnuQgghhM5IcRdCCCF0Roq7EEIIoTNS3IUQQgidkeIuhBBC6IwUdyGEEEJnpLgLIYQQOiPFXQghhNAZKe5CCCGEzkhxF0IIIXRGirsQQgihM1LchRBCCJ2R4i6EEELojCnZDUgUpRQAIXpAJbkxCacluwHJoc67N/o8d34e5+GAP9lNSAqvJ5LsJiSc19ubszqNa5umTidKBw4dOkRJSUmymyGEEEKclbq6OoqLi08ac94U90gkQn19PQ6HA01L7Cd8t9tNSUkJdXV1OJ3OhD53Mknekvf5QPKWvBNFKYXH46GwsBCD4eR31c+bYXmDwXDKTzrDzel0nlcnwTGS9/lF8j6/SN6J5XK5TitOJtQJIYQQOiPFXQghhNAZKe4JYLVaefDBB7FarcluSkJJ3pL3+UDylrxHovNmQp0QQghxvpCeuxBCCKEzUtyFEEIInZHiLoQQQuiMFHchhBBCZ6S4CyGEEDojxV0IIYTQGSnuQgghhM5IcRdCCCF0Roq7EEIIoTNS3IUQQgidkeIuhBBC6IwUdyGEEEJnpLgLIYQQOiPFXQghhNAZKe5CCCGEzkhxF0IIIXRGirsQQgihM1LchRBCCJ2R4i6EEELojBT3M/Tf//3flJWVYbPZmDdvHuvXrx8wdseOHdx0002UlZWhaRpPPPFEv5gPP/yQ6667jsLCQjRN469//evwNf4sDCZvgD//+c9MmDABm83G1KlTefPNN2Mef+ihh5gwYQJpaWlkZGSwZMkS1q1bN5wpnJGhzvvuu+9G07SY5corrxzOFM7IUOd9Ys7Hlv/4j/8YzjQGbTB5//a3v2XhwoVkZGREj+Hj43t6evje977H1KlTSUtLo7CwkC984QvU19cnIpVBGUzeixcvjvteXnPNNdGYV155hcsvv5ysrCw0TaOysjIBWQgAlBi0F198UVksFvX000+rHTt2qHvvvVelp6erpqamuPHr169X3/nOd9QLL7yg8vPz1eOPP94v5s0331Q/+MEP1CuvvKIA9eqrrw5vEmdgsHmvXr1aGY1G9eijj6qdO3eqH/7wh8psNqtt27ZFY5577jn17rvvqurqarV9+3b1pS99STmdTnXkyJFEpXVKw5H3XXfdpa688krV0NAQXdra2hKV0mkZjryPz7ehoUE9/fTTStM0VV1dnai0TmmweX/uc59T//3f/602b96sdu3ape6++27lcrnUoUOHlFJKdXR0qCVLlqiXXnpJ7d69W61du1bNnTtXzZ49O5FpndJg825tbY15L7dv366MRqN65plnojHPPvus+vGPf6x++9vfKkBt3rw5MckIJcX9DMydO1f90z/9U/TvcDisCgsL1SOPPHLKbUtLS+MW9+ON1OI+2LxvvfVWdc0118Ssmzdvnvo//+f/DPgcnZ2dClDLly8fmkYPgeHI+6677lI33HDDsLR3qCTi/b7hhhvUpz71qaFp8BA5m/NbKaVCoZByOBzqD3/4w4Ax69evV4Cqra096/YOlbPN+/HHH1cOh0N5vd5+jx04cECKe4LJsPwgBYNBNm7cyJIlS6LrDAYDS5YsYe3atUls2fA6k7zXrl0bEw9wxRVXDBgfDAZ56qmncLlcTJ8+fegafxaGM++VK1eSm5vL+PHj+drXvkZra+vQJ3CGEvF+NzU18cYbb/ClL31p6Bp+lobi/Pb5fPT09JCZmTlgTGdnJ5qmkZ6efrZNHhJDkffvfvc7brvtNtLS0oarmWIQpLgPUktLC+FwmLy8vJj1eXl5NDY2JqlVw+9M8m5sbDyt+Ndffx273Y7NZuPxxx/n3XffJTs7e2gTOEPDlfeVV17Js88+y4oVK/j3f/93PvjgA6666irC4fDQJ3EGhvP9PuYPf/gDDoeDz3zmM0PT6CEwFOf39773PQoLC/t90DnG7/fzve99j9tvvx2n03nWbR4KZ5v3+vXr2b59O1/+8peHq4likEzJboAQl156KZWVlbS0tPDb3/6WW2+9lXXr1pGbm5vspg2b2267LfrvqVOnMm3aNMaOHcvKlSu57LLLktiyxHn66ae54447sNlsyW7KkPnZz37Giy++yMqVK+Pm1dPTw6233opSil/96ldJaOHw+N3vfsfUqVOZO3duspsijpKe+yBlZ2djNBppamqKWd/U1ER+fn6SWjX8ziTv/Pz804pPS0ujvLycCy+8kN/97neYTCZ+97vfDW0CZ2g48z7emDFjyM7Opqqq6uwbPQSGO++PPvqIPXv2jLie3tmc34899hg/+9nPeOedd5g2bVq/x48V9traWt59990R02uHs8u7q6uLF198cUTdXhFS3AfNYrEwe/ZsVqxYEV0XiURYsWIF8+fPT2LLhteZ5D1//vyYeIB33333lK9TJBIhEAicfaOHQKLyPnToEK2trRQUFAxNw8/ScOf9u9/9jtmzZ4+YuRXHnOn5/eijj/KTn/yEt99+mzlz5vR7/Fhh37dvH8uXLycrK2tY2n+mzua69uc//5lAIMDnP//54W6mGIxkz+g7F7344ovKarWq3//+92rnzp3qK1/5ikpPT1eNjY1KKaXuvPNO9f3vfz8aHwgE1ObNm9XmzZtVQUGB+s53vqM2b96s9u3bF43xeDzRGED953/+p9q8efOImk072LxXr16tTCaTeuyxx9SuXbvUgw8+GPPVKK/Xq5YtW6bWrl2rampq1IYNG9Q999yjrFar2r59e1JyjGeo8/Z4POo73/mOWrt2rTpw4IBavny5mjVrlqqoqFB+vz8pOcYz1Hkf09nZqVJTU9WvfvWrhOZzugab989+9jNlsVjUX/7yl5ivhnk8HqWUUsFgUF1//fWquLhYVVZWxsQEAoGk5BjPYPM+5uKLL1af/exn4+6ztbVVbd68Wb3xxhsKUC+++KLavHmzamhoGNZchHwV7oz94he/UKNGjVIWi0XNnTtXffzxx9HHFi1apO66667o38e+BnLismjRomjM+++/Hzfm+P2MBIPJWyml/vSnP6lx48Ypi8WiJk+erN54443oY93d3erTn/60KiwsVBaLRRUUFKjrr79erV+/PlHpnLahzNvn86nLL79c5eTkKLPZrEpLS9W9994bvYiOJEOZ9zG/+c1vVEpKiuro6Bju5p+xweRdWloa99x98MEHlVIDn/+Aev/99xOb2CkM9v3evXu3AtQ777wTd3/PPPPMSV8bMXw0pZRKyBCBEEIIIRJC7rkLIYQQOiPFXQghhNAZKe5CCCGEzkhxF0IIIXRGirsQQgihM1LchRBCCJ2R4i6EEELojBR3IYQQQmekuAshhBA6I8VdCCGE0Bkp7kIIIYTO/P85oX0EJRhUegAAAABJRU5ErkJggg=="
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": "'this is my life .'"
     },
     "execution_count": 29,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "translator(u'esta es mi vida.')"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2024-05-06T03:11:41.298875400Z",
     "start_time": "2024-05-06T03:11:40.874116700Z"
    }
   }
  }
 ],
 "metadata": {
  "kernelspec": {
   "name": "python3",
   "language": "python",
   "display_name": "Python 3 (ipykernel)"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.8"
  },
  "orig_nbformat": 4,
  "colab": {
   "provenance": [],
   "gpuType": "V100"
  },
  "accelerator": "GPU",
  "widgets": {
   "application/vnd.jupyter.widget-state+json": {
    "267a9f8d838c4649b208914938b1bcff": {
     "model_module": "@jupyter-widgets/controls",
     "model_name": "HBoxModel",
     "model_module_version": "1.5.0",
     "state": {
      "_dom_classes": [],
      "_model_module": "@jupyter-widgets/controls",
      "_model_module_version": "1.5.0",
      "_model_name": "HBoxModel",
      "_view_count": null,
      "_view_module": "@jupyter-widgets/controls",
      "_view_module_version": "1.5.0",
      "_view_name": "HBoxView",
      "box_style": "",
      "children": [
       "IPY_MODEL_a9552c62dcb4441fbca47f89e939759d",
       "IPY_MODEL_7dc472c2f73f4443a0e8437074e67476",
       "IPY_MODEL_c46cefacefb54be7ad60ca93855de3ca"
      ],
      "layout": "IPY_MODEL_9ebbd2d91c9849baaa85cff5b2b048e1"
     }
    },
    "a9552c62dcb4441fbca47f89e939759d": {
     "model_module": "@jupyter-widgets/controls",
     "model_name": "HTMLModel",
     "model_module_version": "1.5.0",
     "state": {
      "_dom_classes": [],
      "_model_module": "@jupyter-widgets/controls",
      "_model_module_version": "1.5.0",
      "_model_name": "HTMLModel",
      "_view_count": null,
      "_view_module": "@jupyter-widgets/controls",
      "_view_module_version": "1.5.0",
      "_view_name": "HTMLView",
      "description": "",
      "description_tooltip": null,
      "layout": "IPY_MODEL_63c6ee4650cb4a938e9f325113e259d1",
      "placeholder": "​",
      "style": "IPY_MODEL_95d9e57c587f43e6ba5f656f2b2e5c71",
      "value": " 23%"
     }
    },
    "7dc472c2f73f4443a0e8437074e67476": {
     "model_module": "@jupyter-widgets/controls",
     "model_name": "FloatProgressModel",
     "model_module_version": "1.5.0",
     "state": {
      "_dom_classes": [],
      "_model_module": "@jupyter-widgets/controls",
      "_model_module_version": "1.5.0",
      "_model_name": "FloatProgressModel",
      "_view_count": null,
      "_view_module": "@jupyter-widgets/controls",
      "_view_module_version": "1.5.0",
      "_view_name": "ProgressView",
      "bar_style": "danger",
      "description": "",
      "description_tooltip": null,
      "layout": "IPY_MODEL_863e7ad581894502979884fe0e9e412e",
      "max": 33420,
      "min": 0,
      "orientation": "horizontal",
      "style": "IPY_MODEL_7d21bf5788794ed2b0b4dc4a98a5d2e9",
      "value": 7599
     }
    },
    "c46cefacefb54be7ad60ca93855de3ca": {
     "model_module": "@jupyter-widgets/controls",
     "model_name": "HTMLModel",
     "model_module_version": "1.5.0",
     "state": {
      "_dom_classes": [],
      "_model_module": "@jupyter-widgets/controls",
      "_model_module_version": "1.5.0",
      "_model_name": "HTMLModel",
      "_view_count": null,
      "_view_module": "@jupyter-widgets/controls",
      "_view_module_version": "1.5.0",
      "_view_name": "HTMLView",
      "description": "",
      "description_tooltip": null,
      "layout": "IPY_MODEL_296304e90e43440094ba467cafb20896",
      "placeholder": "​",
      "style": "IPY_MODEL_c3d8fddae7354c278c8e88291dbcee8d",
      "value": " 7599/33420 [09:31&lt;23:51, 18.03it/s, epoch=3, loss=1.2, val_loss=1.26]"
     }
    },
    "9ebbd2d91c9849baaa85cff5b2b048e1": {
     "model_module": "@jupyter-widgets/base",
     "model_name": "LayoutModel",
     "model_module_version": "1.2.0",
     "state": {
      "_model_module": "@jupyter-widgets/base",
      "_model_module_version": "1.2.0",
      "_model_name": "LayoutModel",
      "_view_count": null,
      "_view_module": "@jupyter-widgets/base",
      "_view_module_version": "1.2.0",
      "_view_name": "LayoutView",
      "align_content": null,
      "align_items": null,
      "align_self": null,
      "border": null,
      "bottom": null,
      "display": null,
      "flex": null,
      "flex_flow": null,
      "grid_area": null,
      "grid_auto_columns": null,
      "grid_auto_flow": null,
      "grid_auto_rows": null,
      "grid_column": null,
      "grid_gap": null,
      "grid_row": null,
      "grid_template_areas": null,
      "grid_template_columns": null,
      "grid_template_rows": null,
      "height": null,
      "justify_content": null,
      "justify_items": null,
      "left": null,
      "margin": null,
      "max_height": null,
      "max_width": null,
      "min_height": null,
      "min_width": null,
      "object_fit": null,
      "object_position": null,
      "order": null,
      "overflow": null,
      "overflow_x": null,
      "overflow_y": null,
      "padding": null,
      "right": null,
      "top": null,
      "visibility": null,
      "width": null
     }
    },
    "63c6ee4650cb4a938e9f325113e259d1": {
     "model_module": "@jupyter-widgets/base",
     "model_name": "LayoutModel",
     "model_module_version": "1.2.0",
     "state": {
      "_model_module": "@jupyter-widgets/base",
      "_model_module_version": "1.2.0",
      "_model_name": "LayoutModel",
      "_view_count": null,
      "_view_module": "@jupyter-widgets/base",
      "_view_module_version": "1.2.0",
      "_view_name": "LayoutView",
      "align_content": null,
      "align_items": null,
      "align_self": null,
      "border": null,
      "bottom": null,
      "display": null,
      "flex": null,
      "flex_flow": null,
      "grid_area": null,
      "grid_auto_columns": null,
      "grid_auto_flow": null,
      "grid_auto_rows": null,
      "grid_column": null,
      "grid_gap": null,
      "grid_row": null,
      "grid_template_areas": null,
      "grid_template_columns": null,
      "grid_template_rows": null,
      "height": null,
      "justify_content": null,
      "justify_items": null,
      "left": null,
      "margin": null,
      "max_height": null,
      "max_width": null,
      "min_height": null,
      "min_width": null,
      "object_fit": null,
      "object_position": null,
      "order": null,
      "overflow": null,
      "overflow_x": null,
      "overflow_y": null,
      "padding": null,
      "right": null,
      "top": null,
      "visibility": null,
      "width": null
     }
    },
    "95d9e57c587f43e6ba5f656f2b2e5c71": {
     "model_module": "@jupyter-widgets/controls",
     "model_name": "DescriptionStyleModel",
     "model_module_version": "1.5.0",
     "state": {
      "_model_module": "@jupyter-widgets/controls",
      "_model_module_version": "1.5.0",
      "_model_name": "DescriptionStyleModel",
      "_view_count": null,
      "_view_module": "@jupyter-widgets/base",
      "_view_module_version": "1.2.0",
      "_view_name": "StyleView",
      "description_width": ""
     }
    },
    "863e7ad581894502979884fe0e9e412e": {
     "model_module": "@jupyter-widgets/base",
     "model_name": "LayoutModel",
     "model_module_version": "1.2.0",
     "state": {
      "_model_module": "@jupyter-widgets/base",
      "_model_module_version": "1.2.0",
      "_model_name": "LayoutModel",
      "_view_count": null,
      "_view_module": "@jupyter-widgets/base",
      "_view_module_version": "1.2.0",
      "_view_name": "LayoutView",
      "align_content": null,
      "align_items": null,
      "align_self": null,
      "border": null,
      "bottom": null,
      "display": null,
      "flex": null,
      "flex_flow": null,
      "grid_area": null,
      "grid_auto_columns": null,
      "grid_auto_flow": null,
      "grid_auto_rows": null,
      "grid_column": null,
      "grid_gap": null,
      "grid_row": null,
      "grid_template_areas": null,
      "grid_template_columns": null,
      "grid_template_rows": null,
      "height": null,
      "justify_content": null,
      "justify_items": null,
      "left": null,
      "margin": null,
      "max_height": null,
      "max_width": null,
      "min_height": null,
      "min_width": null,
      "object_fit": null,
      "object_position": null,
      "order": null,
      "overflow": null,
      "overflow_x": null,
      "overflow_y": null,
      "padding": null,
      "right": null,
      "top": null,
      "visibility": null,
      "width": null
     }
    },
    "7d21bf5788794ed2b0b4dc4a98a5d2e9": {
     "model_module": "@jupyter-widgets/controls",
     "model_name": "ProgressStyleModel",
     "model_module_version": "1.5.0",
     "state": {
      "_model_module": "@jupyter-widgets/controls",
      "_model_module_version": "1.5.0",
      "_model_name": "ProgressStyleModel",
      "_view_count": null,
      "_view_module": "@jupyter-widgets/base",
      "_view_module_version": "1.2.0",
      "_view_name": "StyleView",
      "bar_color": null,
      "description_width": ""
     }
    },
    "296304e90e43440094ba467cafb20896": {
     "model_module": "@jupyter-widgets/base",
     "model_name": "LayoutModel",
     "model_module_version": "1.2.0",
     "state": {
      "_model_module": "@jupyter-widgets/base",
      "_model_module_version": "1.2.0",
      "_model_name": "LayoutModel",
      "_view_count": null,
      "_view_module": "@jupyter-widgets/base",
      "_view_module_version": "1.2.0",
      "_view_name": "LayoutView",
      "align_content": null,
      "align_items": null,
      "align_self": null,
      "border": null,
      "bottom": null,
      "display": null,
      "flex": null,
      "flex_flow": null,
      "grid_area": null,
      "grid_auto_columns": null,
      "grid_auto_flow": null,
      "grid_auto_rows": null,
      "grid_column": null,
      "grid_gap": null,
      "grid_row": null,
      "grid_template_areas": null,
      "grid_template_columns": null,
      "grid_template_rows": null,
      "height": null,
      "justify_content": null,
      "justify_items": null,
      "left": null,
      "margin": null,
      "max_height": null,
      "max_width": null,
      "min_height": null,
      "min_width": null,
      "object_fit": null,
      "object_position": null,
      "order": null,
      "overflow": null,
      "overflow_x": null,
      "overflow_y": null,
      "padding": null,
      "right": null,
      "top": null,
      "visibility": null,
      "width": null
     }
    },
    "c3d8fddae7354c278c8e88291dbcee8d": {
     "model_module": "@jupyter-widgets/controls",
     "model_name": "DescriptionStyleModel",
     "model_module_version": "1.5.0",
     "state": {
      "_model_module": "@jupyter-widgets/controls",
      "_model_module_version": "1.5.0",
      "_model_name": "DescriptionStyleModel",
      "_view_count": null,
      "_view_module": "@jupyter-widgets/base",
      "_view_module_version": "1.2.0",
      "_view_name": "StyleView",
      "description_width": ""
     }
    }
   }
  }
 },
 "nbformat": 4,
 "nbformat_minor": 0
}
